/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/DumpRegisterValue.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 23 | lldb_private::Stream &strm) { |
29 | 23 | 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 | 23 | if (target_order == lldb::ByteOrder::eByteOrderLittle) { |
37 | 23 | value = reg_info.flags_type->ReverseFieldOrder(value); |
38 | 23 | } |
39 | | |
40 | | // Then we need to match the target's endian on a byte level as well. |
41 | 23 | if (lldb_private::endian::InlHostByteOrder() != target_order) |
42 | 0 | value = llvm::byteswap(value); |
43 | | |
44 | 23 | lldb_private::DataExtractor data_extractor{ |
45 | 23 | &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8}; |
46 | | |
47 | 23 | lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create( |
48 | 23 | exe_scope, fields_type, lldb_private::ConstString(), data_extractor); |
49 | 23 | lldb_private::DumpValueObjectOptions dump_options; |
50 | 23 | lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider = |
51 | 54 | [](lldb_private::ConstString varname) { |
52 | | // Unnamed bit-fields are padding that we don't want to show. |
53 | 54 | return varname.GetLength(); |
54 | 54 | }; DumpRegisterValue.cpp:void dump_type_value<unsigned int>(lldb_private::CompilerType&, unsigned int, lldb_private::ExecutionContextScope*, lldb_private::RegisterInfo const&, lldb_private::Stream&)::'lambda'(lldb_private::ConstString)::operator()(lldb_private::ConstString) const Line | Count | Source | 51 | 43 | [](lldb_private::ConstString varname) { | 52 | | // Unnamed bit-fields are padding that we don't want to show. | 53 | 43 | return varname.GetLength(); | 54 | 43 | }; |
DumpRegisterValue.cpp:void dump_type_value<unsigned long long>(lldb_private::CompilerType&, unsigned long long, lldb_private::ExecutionContextScope*, lldb_private::RegisterInfo const&, lldb_private::Stream&)::'lambda'(lldb_private::ConstString)::operator()(lldb_private::ConstString) const Line | Count | Source | 51 | 11 | [](lldb_private::ConstString varname) { | 52 | | // Unnamed bit-fields are padding that we don't want to show. | 53 | 11 | return varname.GetLength(); | 54 | 11 | }; |
|
55 | 23 | dump_options.SetChildPrintingDecider(decider).SetHideRootType(true); |
56 | | |
57 | 23 | vobj_sp->Dump(strm, dump_options); |
58 | 23 | } DumpRegisterValue.cpp:void dump_type_value<unsigned int>(lldb_private::CompilerType&, unsigned int, lldb_private::ExecutionContextScope*, lldb_private::RegisterInfo const&, lldb_private::Stream&) Line | Count | Source | 28 | 18 | lldb_private::Stream &strm) { | 29 | 18 | 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 | 18 | if (target_order == lldb::ByteOrder::eByteOrderLittle) { | 37 | 18 | value = reg_info.flags_type->ReverseFieldOrder(value); | 38 | 18 | } | 39 | | | 40 | | // Then we need to match the target's endian on a byte level as well. | 41 | 18 | if (lldb_private::endian::InlHostByteOrder() != target_order) | 42 | 0 | value = llvm::byteswap(value); | 43 | | | 44 | 18 | lldb_private::DataExtractor data_extractor{ | 45 | 18 | &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8}; | 46 | | | 47 | 18 | lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create( | 48 | 18 | exe_scope, fields_type, lldb_private::ConstString(), data_extractor); | 49 | 18 | lldb_private::DumpValueObjectOptions dump_options; | 50 | 18 | lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider = | 51 | 18 | [](lldb_private::ConstString varname) { | 52 | | // Unnamed bit-fields are padding that we don't want to show. | 53 | 18 | return varname.GetLength(); | 54 | 18 | }; | 55 | 18 | dump_options.SetChildPrintingDecider(decider).SetHideRootType(true); | 56 | | | 57 | 18 | vobj_sp->Dump(strm, dump_options); | 58 | 18 | } |
DumpRegisterValue.cpp:void dump_type_value<unsigned long long>(lldb_private::CompilerType&, unsigned long long, lldb_private::ExecutionContextScope*, lldb_private::RegisterInfo const&, lldb_private::Stream&) Line | Count | Source | 28 | 5 | lldb_private::Stream &strm) { | 29 | 5 | 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 | 5 | if (target_order == lldb::ByteOrder::eByteOrderLittle) { | 37 | 5 | value = reg_info.flags_type->ReverseFieldOrder(value); | 38 | 5 | } | 39 | | | 40 | | // Then we need to match the target's endian on a byte level as well. | 41 | 5 | if (lldb_private::endian::InlHostByteOrder() != target_order) | 42 | 0 | value = llvm::byteswap(value); | 43 | | | 44 | 5 | lldb_private::DataExtractor data_extractor{ | 45 | 5 | &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8}; | 46 | | | 47 | 5 | lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create( | 48 | 5 | exe_scope, fields_type, lldb_private::ConstString(), data_extractor); | 49 | 5 | lldb_private::DumpValueObjectOptions dump_options; | 50 | 5 | lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider = | 51 | 5 | [](lldb_private::ConstString varname) { | 52 | | // Unnamed bit-fields are padding that we don't want to show. | 53 | 5 | return varname.GetLength(); | 54 | 5 | }; | 55 | 5 | dump_options.SetChildPrintingDecider(decider).SetHideRootType(true); | 56 | | | 57 | 5 | vobj_sp->Dump(strm, dump_options); | 58 | 5 | } |
|
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 | 6.74k | bool print_flags, TargetSP target_sp) { |
67 | 6.74k | DataExtractor data; |
68 | 6.74k | if (!reg_val.GetData(data)) |
69 | 0 | return; |
70 | | |
71 | 6.74k | 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 | 6.74k | StreamString format_string; |
78 | 6.74k | if (reg_name_right_align_at && (prefix_with_name ^ prefix_with_alt_name)) |
79 | 6.74k | format_string.Printf("%%%us", reg_name_right_align_at); |
80 | 0 | else |
81 | 0 | format_string.Printf("%%s"); |
82 | 6.74k | std::string fmt = std::string(format_string.GetString()); |
83 | 6.74k | if (prefix_with_name) { |
84 | 6.74k | if (reg_info.name) { |
85 | 6.74k | s.Printf(fmt.c_str(), reg_info.name); |
86 | 6.74k | name_printed = true; |
87 | 6.74k | } else if (0 reg_info.alt_name0 ) { |
88 | 0 | s.Printf(fmt.c_str(), reg_info.alt_name); |
89 | 0 | prefix_with_alt_name = false; |
90 | 0 | name_printed = true; |
91 | 0 | } |
92 | 6.74k | } |
93 | 6.74k | if (prefix_with_alt_name) { |
94 | 0 | if (name_printed) |
95 | 0 | s.PutChar('/'); |
96 | 0 | if (reg_info.alt_name) { |
97 | 0 | s.Printf(fmt.c_str(), reg_info.alt_name); |
98 | 0 | name_printed = true; |
99 | 0 | } else if (!name_printed) { |
100 | | // No alternate name but we were asked to display a name, so show the |
101 | | // main name |
102 | 0 | s.Printf(fmt.c_str(), reg_info.name); |
103 | 0 | name_printed = true; |
104 | 0 | } |
105 | 0 | } |
106 | 6.74k | if (name_printed) |
107 | 6.74k | s.PutCString(" = "); |
108 | | |
109 | 6.74k | if (format == eFormatDefault) |
110 | 6.74k | format = reg_info.format; |
111 | | |
112 | 6.74k | DumpDataExtractor(data, &s, |
113 | 6.74k | 0, // Offset in "data" |
114 | 6.74k | format, // Format to use when dumping |
115 | 6.74k | reg_info.byte_size, // item_byte_size |
116 | 6.74k | 1, // item_count |
117 | 6.74k | UINT32_MAX, // num_per_line |
118 | 6.74k | LLDB_INVALID_ADDRESS, // base_addr |
119 | 6.74k | 0, // item_bit_size |
120 | 6.74k | 0, // item_bit_offset |
121 | 6.74k | exe_scope); |
122 | | |
123 | 6.74k | if (!print_flags || !reg_info.flags_type589 || !exe_scope23 || !target_sp23 || |
124 | 6.74k | (23 reg_info.byte_size != 423 && reg_info.byte_size != 85 )) |
125 | 6.72k | return; |
126 | | |
127 | 23 | CompilerType fields_type = target_sp->GetRegisterType( |
128 | 23 | reg_info.name, *reg_info.flags_type, reg_info.byte_size); |
129 | | |
130 | | // Use a new stream so we can remove a trailing newline later. |
131 | 23 | StreamString fields_stream; |
132 | | |
133 | 23 | if (reg_info.byte_size == 4) { |
134 | 18 | dump_type_value(fields_type, reg_val.GetAsUInt32(), exe_scope, reg_info, |
135 | 18 | fields_stream); |
136 | 18 | } else { |
137 | 5 | dump_type_value(fields_type, reg_val.GetAsUInt64(), exe_scope, reg_info, |
138 | 5 | fields_stream); |
139 | 5 | } |
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 | 23 | llvm::StringRef fields_str = fields_stream.GetString().drop_back(); |
149 | | |
150 | | // End the line that contains " foo = 0x12345678". |
151 | 23 | s.EOL(); |
152 | | |
153 | | // Then split the value lines and indent each one. |
154 | 23 | bool first = true; |
155 | 51 | while (fields_str.size()) { |
156 | 28 | std::pair<llvm::StringRef, llvm::StringRef> split = fields_str.split('\n'); |
157 | 28 | fields_str = split.second; |
158 | | // Indent as far as the register name did. |
159 | 28 | s.Printf(fmt.c_str(), ""); |
160 | | |
161 | | // Lines after the first won't have " = " so compensate for that. |
162 | 28 | if (!first) |
163 | 5 | s << " "; |
164 | 28 | first = false; |
165 | | |
166 | 28 | s << split.first; |
167 | | |
168 | | // On the last line we don't want a newline because the command will add |
169 | | // one too. |
170 | 28 | if (fields_str.size()) |
171 | 5 | s.EOL(); |
172 | 28 | } |
173 | 23 | } |