1 | //===-- DumpRegisterValue.cpp ---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Core/DumpRegisterValue.h" |
10 | #include "lldb/Core/DumpDataExtractor.h" |
11 | #include "lldb/Core/ValueObject.h" |
12 | #include "lldb/Core/ValueObjectConstResult.h" |
13 | #include "lldb/DataFormatters/DumpValueObjectOptions.h" |
14 | #include "lldb/Target/RegisterFlags.h" |
15 | #include "lldb/Utility/DataExtractor.h" |
16 | #include "lldb/Utility/Endian.h" |
17 | #include "lldb/Utility/RegisterValue.h" |
18 | #include "lldb/Utility/StreamString.h" |
19 | #include "lldb/lldb-private-types.h" |
20 | #include "llvm/ADT/bit.h" |
21 | |
22 | using namespace lldb; |
23 | |
24 | template <typename T> |
25 | static void dump_type_value(lldb_private::CompilerType &fields_type, T value, |
26 | lldb_private::ExecutionContextScope *exe_scope, |
27 | const lldb_private::RegisterInfo ®_info, |
28 | lldb_private::Stream &strm) { |
29 | lldb::ByteOrder target_order = exe_scope->CalculateProcess()->GetByteOrder(); |
30 | |
31 | // For the bitfield types we generate, it is expected that the fields are |
32 | // in what is usually a big endian order. Most significant field first. |
33 | // This is also clang's internal ordering and the order we want to print |
34 | // them. On a big endian host this all matches up, for a little endian |
35 | // host we have to swap the order of the fields before display. |
36 | if (target_order == lldb::ByteOrder::eByteOrderLittle) { |
37 | value = reg_info.flags_type->ReverseFieldOrder(value); |
38 | } |
39 | |
40 | // Then we need to match the target's endian on a byte level as well. |
41 | if (lldb_private::endian::InlHostByteOrder() != target_order) |
42 | value = llvm::byteswap(value); |
43 | |
44 | lldb_private::DataExtractor { |
45 | &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8}; |
46 | |
47 | lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create( |
48 | exe_scope, compiler_type: fields_type, name: lldb_private::ConstString(), data: data_extractor); |
49 | lldb_private::DumpValueObjectOptions dump_options; |
50 | lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider = |
51 | [](lldb_private::ConstString varname) { |
52 | // Unnamed bit-fields are padding that we don't want to show. |
53 | return varname.GetLength(); |
54 | }; |
55 | dump_options.SetChildPrintingDecider(decider).SetHideRootType(true); |
56 | |
57 | vobj_sp->Dump(s&: strm, options: dump_options); |
58 | } |
59 | |
60 | void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s, |
61 | const RegisterInfo ®_info, |
62 | bool prefix_with_name, |
63 | bool prefix_with_alt_name, Format format, |
64 | uint32_t reg_name_right_align_at, |
65 | ExecutionContextScope *exe_scope, |
66 | bool print_flags, TargetSP target_sp) { |
67 | DataExtractor data; |
68 | if (!reg_val.GetData(data)) |
69 | return; |
70 | |
71 | bool name_printed = false; |
72 | // For simplicity, alignment of the register name printing applies only in |
73 | // the most common case where: |
74 | // |
75 | // prefix_with_name^prefix_with_alt_name is true |
76 | // |
77 | StreamString format_string; |
78 | if (reg_name_right_align_at && (prefix_with_name ^ prefix_with_alt_name)) |
79 | format_string.Printf(format: "%%%us" , reg_name_right_align_at); |
80 | else |
81 | format_string.Printf(format: "%%s" ); |
82 | std::string fmt = std::string(format_string.GetString()); |
83 | if (prefix_with_name) { |
84 | if (reg_info.name) { |
85 | s.Printf(format: fmt.c_str(), reg_info.name); |
86 | name_printed = true; |
87 | } else if (reg_info.alt_name) { |
88 | s.Printf(format: fmt.c_str(), reg_info.alt_name); |
89 | prefix_with_alt_name = false; |
90 | name_printed = true; |
91 | } |
92 | } |
93 | if (prefix_with_alt_name) { |
94 | if (name_printed) |
95 | s.PutChar(ch: '/'); |
96 | if (reg_info.alt_name) { |
97 | s.Printf(format: fmt.c_str(), reg_info.alt_name); |
98 | name_printed = true; |
99 | } else if (!name_printed) { |
100 | // No alternate name but we were asked to display a name, so show the |
101 | // main name |
102 | s.Printf(format: fmt.c_str(), reg_info.name); |
103 | name_printed = true; |
104 | } |
105 | } |
106 | if (name_printed) |
107 | s.PutCString(cstr: " = " ); |
108 | |
109 | if (format == eFormatDefault) |
110 | format = reg_info.format; |
111 | |
112 | DumpDataExtractor(DE: data, s: &s, |
113 | offset: 0, // Offset in "data" |
114 | item_format: format, // Format to use when dumping |
115 | item_byte_size: reg_info.byte_size, // item_byte_size |
116 | item_count: 1, // item_count |
117 | UINT32_MAX, // num_per_line |
118 | LLDB_INVALID_ADDRESS, // base_addr |
119 | item_bit_size: 0, // item_bit_size |
120 | item_bit_offset: 0, // item_bit_offset |
121 | exe_scope); |
122 | |
123 | if (!print_flags || !reg_info.flags_type || !exe_scope || !target_sp || |
124 | (reg_info.byte_size != 4 && reg_info.byte_size != 8)) |
125 | return; |
126 | |
127 | CompilerType fields_type = target_sp->GetRegisterType( |
128 | name: reg_info.name, flags: *reg_info.flags_type, byte_size: reg_info.byte_size); |
129 | |
130 | // Use a new stream so we can remove a trailing newline later. |
131 | StreamString fields_stream; |
132 | |
133 | if (reg_info.byte_size == 4) { |
134 | dump_type_value(fields_type, value: reg_val.GetAsUInt32(), exe_scope, reg_info, |
135 | strm&: fields_stream); |
136 | } else { |
137 | dump_type_value(fields_type, value: reg_val.GetAsUInt64(), exe_scope, reg_info, |
138 | strm&: fields_stream); |
139 | } |
140 | |
141 | // Registers are indented like: |
142 | // (lldb) register read foo |
143 | // foo = 0x12345678 |
144 | // So we need to indent to match that. |
145 | |
146 | // First drop the extra newline that the value printer added. The register |
147 | // command will add one itself. |
148 | llvm::StringRef fields_str = fields_stream.GetString().drop_back(); |
149 | |
150 | // End the line that contains " foo = 0x12345678". |
151 | s.EOL(); |
152 | |
153 | // Then split the value lines and indent each one. |
154 | bool first = true; |
155 | while (fields_str.size()) { |
156 | std::pair<llvm::StringRef, llvm::StringRef> split = fields_str.split(Separator: '\n'); |
157 | fields_str = split.second; |
158 | // Indent as far as the register name did. |
159 | s.Printf(format: fmt.c_str(), "" ); |
160 | |
161 | // Lines after the first won't have " = " so compensate for that. |
162 | if (!first) |
163 | s << " " ; |
164 | first = false; |
165 | |
166 | s << split.first; |
167 | |
168 | // On the last line we don't want a newline because the command will add |
169 | // one too. |
170 | if (fields_str.size()) |
171 | s.EOL(); |
172 | } |
173 | } |
174 | |