15ffd83dbSDimitry Andric //===-- DumpRegisterValue.cpp ---------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h" 100b57cec5SDimitry Andric #include "lldb/Core/DumpDataExtractor.h" 1106c3fb27SDimitry Andric #include "lldb/Core/ValueObject.h" 1206c3fb27SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h" 1306c3fb27SDimitry Andric #include "lldb/DataFormatters/DumpValueObjectOptions.h" 1406c3fb27SDimitry Andric #include "lldb/Target/RegisterFlags.h" 150b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h" 1606c3fb27SDimitry Andric #include "lldb/Utility/Endian.h" 170b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h" 180b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h" 190b57cec5SDimitry Andric #include "lldb/lldb-private-types.h" 2006c3fb27SDimitry Andric #include "llvm/ADT/bit.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace lldb; 230b57cec5SDimitry Andric 2406c3fb27SDimitry Andric template <typename T> 2506c3fb27SDimitry Andric static void dump_type_value(lldb_private::CompilerType &fields_type, T value, 2606c3fb27SDimitry Andric lldb_private::ExecutionContextScope *exe_scope, 2706c3fb27SDimitry Andric const lldb_private::RegisterInfo ®_info, 2806c3fb27SDimitry Andric lldb_private::Stream &strm) { 2906c3fb27SDimitry Andric lldb::ByteOrder target_order = exe_scope->CalculateProcess()->GetByteOrder(); 3006c3fb27SDimitry Andric 3106c3fb27SDimitry Andric // For the bitfield types we generate, it is expected that the fields are 3206c3fb27SDimitry Andric // in what is usually a big endian order. Most significant field first. 3306c3fb27SDimitry Andric // This is also clang's internal ordering and the order we want to print 3406c3fb27SDimitry Andric // them. On a big endian host this all matches up, for a little endian 3506c3fb27SDimitry Andric // host we have to swap the order of the fields before display. 3606c3fb27SDimitry Andric if (target_order == lldb::ByteOrder::eByteOrderLittle) { 3706c3fb27SDimitry Andric value = reg_info.flags_type->ReverseFieldOrder(value); 3806c3fb27SDimitry Andric } 3906c3fb27SDimitry Andric 4006c3fb27SDimitry Andric // Then we need to match the target's endian on a byte level as well. 4106c3fb27SDimitry Andric if (lldb_private::endian::InlHostByteOrder() != target_order) 4206c3fb27SDimitry Andric value = llvm::byteswap(value); 4306c3fb27SDimitry Andric 4406c3fb27SDimitry Andric lldb_private::DataExtractor data_extractor{ 4506c3fb27SDimitry Andric &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8}; 4606c3fb27SDimitry Andric 4706c3fb27SDimitry Andric lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create( 4806c3fb27SDimitry Andric exe_scope, fields_type, lldb_private::ConstString(), data_extractor); 4906c3fb27SDimitry Andric lldb_private::DumpValueObjectOptions dump_options; 5006c3fb27SDimitry Andric lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider = 5106c3fb27SDimitry Andric [](lldb_private::ConstString varname) { 5206c3fb27SDimitry Andric // Unnamed bit-fields are padding that we don't want to show. 5306c3fb27SDimitry Andric return varname.GetLength(); 5406c3fb27SDimitry Andric }; 5506c3fb27SDimitry Andric dump_options.SetChildPrintingDecider(decider).SetHideRootType(true); 5606c3fb27SDimitry Andric 57*0fca6ea1SDimitry Andric if (llvm::Error error = vobj_sp->Dump(strm, dump_options)) 58*0fca6ea1SDimitry Andric strm << "error: " << toString(std::move(error)); 5906c3fb27SDimitry Andric } 6006c3fb27SDimitry Andric 6106c3fb27SDimitry Andric void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s, 6206c3fb27SDimitry Andric const RegisterInfo ®_info, 630b57cec5SDimitry Andric bool prefix_with_name, 640b57cec5SDimitry Andric bool prefix_with_alt_name, Format format, 65bdd1243dSDimitry Andric uint32_t reg_name_right_align_at, 6606c3fb27SDimitry Andric ExecutionContextScope *exe_scope, 6706c3fb27SDimitry Andric bool print_flags, TargetSP target_sp) { 680b57cec5SDimitry Andric DataExtractor data; 69bdd1243dSDimitry Andric if (!reg_val.GetData(data)) 70bdd1243dSDimitry Andric return; 71bdd1243dSDimitry Andric 720b57cec5SDimitry Andric bool name_printed = false; 730b57cec5SDimitry Andric // For simplicity, alignment of the register name printing applies only in 740b57cec5SDimitry Andric // the most common case where: 750b57cec5SDimitry Andric // 760b57cec5SDimitry Andric // prefix_with_name^prefix_with_alt_name is true 770b57cec5SDimitry Andric // 780b57cec5SDimitry Andric StreamString format_string; 790b57cec5SDimitry Andric if (reg_name_right_align_at && (prefix_with_name ^ prefix_with_alt_name)) 800b57cec5SDimitry Andric format_string.Printf("%%%us", reg_name_right_align_at); 810b57cec5SDimitry Andric else 820b57cec5SDimitry Andric format_string.Printf("%%s"); 835ffd83dbSDimitry Andric std::string fmt = std::string(format_string.GetString()); 840b57cec5SDimitry Andric if (prefix_with_name) { 8506c3fb27SDimitry Andric if (reg_info.name) { 8606c3fb27SDimitry Andric s.Printf(fmt.c_str(), reg_info.name); 870b57cec5SDimitry Andric name_printed = true; 8806c3fb27SDimitry Andric } else if (reg_info.alt_name) { 8906c3fb27SDimitry Andric s.Printf(fmt.c_str(), reg_info.alt_name); 900b57cec5SDimitry Andric prefix_with_alt_name = false; 910b57cec5SDimitry Andric name_printed = true; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric if (prefix_with_alt_name) { 950b57cec5SDimitry Andric if (name_printed) 9606c3fb27SDimitry Andric s.PutChar('/'); 9706c3fb27SDimitry Andric if (reg_info.alt_name) { 9806c3fb27SDimitry Andric s.Printf(fmt.c_str(), reg_info.alt_name); 990b57cec5SDimitry Andric name_printed = true; 1000b57cec5SDimitry Andric } else if (!name_printed) { 1010b57cec5SDimitry Andric // No alternate name but we were asked to display a name, so show the 1020b57cec5SDimitry Andric // main name 10306c3fb27SDimitry Andric s.Printf(fmt.c_str(), reg_info.name); 1040b57cec5SDimitry Andric name_printed = true; 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric if (name_printed) 10806c3fb27SDimitry Andric s.PutCString(" = "); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric if (format == eFormatDefault) 11106c3fb27SDimitry Andric format = reg_info.format; 1120b57cec5SDimitry Andric 11306c3fb27SDimitry Andric DumpDataExtractor(data, &s, 1140b57cec5SDimitry Andric 0, // Offset in "data" 1150b57cec5SDimitry Andric format, // Format to use when dumping 11606c3fb27SDimitry Andric reg_info.byte_size, // item_byte_size 1170b57cec5SDimitry Andric 1, // item_count 1180b57cec5SDimitry Andric UINT32_MAX, // num_per_line 1190b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, // base_addr 1200b57cec5SDimitry Andric 0, // item_bit_size 121bdd1243dSDimitry Andric 0, // item_bit_offset 122bdd1243dSDimitry Andric exe_scope); 12306c3fb27SDimitry Andric 12406c3fb27SDimitry Andric if (!print_flags || !reg_info.flags_type || !exe_scope || !target_sp || 12506c3fb27SDimitry Andric (reg_info.byte_size != 4 && reg_info.byte_size != 8)) 12606c3fb27SDimitry Andric return; 12706c3fb27SDimitry Andric 12806c3fb27SDimitry Andric CompilerType fields_type = target_sp->GetRegisterType( 12906c3fb27SDimitry Andric reg_info.name, *reg_info.flags_type, reg_info.byte_size); 13006c3fb27SDimitry Andric 13106c3fb27SDimitry Andric // Use a new stream so we can remove a trailing newline later. 13206c3fb27SDimitry Andric StreamString fields_stream; 13306c3fb27SDimitry Andric 13406c3fb27SDimitry Andric if (reg_info.byte_size == 4) { 13506c3fb27SDimitry Andric dump_type_value(fields_type, reg_val.GetAsUInt32(), exe_scope, reg_info, 13606c3fb27SDimitry Andric fields_stream); 13706c3fb27SDimitry Andric } else { 13806c3fb27SDimitry Andric dump_type_value(fields_type, reg_val.GetAsUInt64(), exe_scope, reg_info, 13906c3fb27SDimitry Andric fields_stream); 14006c3fb27SDimitry Andric } 14106c3fb27SDimitry Andric 14206c3fb27SDimitry Andric // Registers are indented like: 14306c3fb27SDimitry Andric // (lldb) register read foo 14406c3fb27SDimitry Andric // foo = 0x12345678 14506c3fb27SDimitry Andric // So we need to indent to match that. 14606c3fb27SDimitry Andric 14706c3fb27SDimitry Andric // First drop the extra newline that the value printer added. The register 14806c3fb27SDimitry Andric // command will add one itself. 14906c3fb27SDimitry Andric llvm::StringRef fields_str = fields_stream.GetString().drop_back(); 15006c3fb27SDimitry Andric 15106c3fb27SDimitry Andric // End the line that contains " foo = 0x12345678". 15206c3fb27SDimitry Andric s.EOL(); 15306c3fb27SDimitry Andric 15406c3fb27SDimitry Andric // Then split the value lines and indent each one. 15506c3fb27SDimitry Andric bool first = true; 15606c3fb27SDimitry Andric while (fields_str.size()) { 15706c3fb27SDimitry Andric std::pair<llvm::StringRef, llvm::StringRef> split = fields_str.split('\n'); 15806c3fb27SDimitry Andric fields_str = split.second; 15906c3fb27SDimitry Andric // Indent as far as the register name did. 16006c3fb27SDimitry Andric s.Printf(fmt.c_str(), ""); 16106c3fb27SDimitry Andric 16206c3fb27SDimitry Andric // Lines after the first won't have " = " so compensate for that. 16306c3fb27SDimitry Andric if (!first) 16406c3fb27SDimitry Andric s << " "; 16506c3fb27SDimitry Andric first = false; 16606c3fb27SDimitry Andric 16706c3fb27SDimitry Andric s << split.first; 16806c3fb27SDimitry Andric 16906c3fb27SDimitry Andric // On the last line we don't want a newline because the command will add 17006c3fb27SDimitry Andric // one too. 17106c3fb27SDimitry Andric if (fields_str.size()) 17206c3fb27SDimitry Andric s.EOL(); 17306c3fb27SDimitry Andric } 1740b57cec5SDimitry Andric } 175