12
12
13
13
#include " llvm/ADT/StringExtras.h"
14
14
15
+ #include < limits>
15
16
#include < numeric>
16
17
#include < optional>
17
18
18
19
using namespace lldb_private ;
19
20
20
21
RegisterFlags::Field::Field (std::string name, unsigned start, unsigned end)
21
- : m_name(std::move(name)), m_start(start), m_end(end) {
22
+ : m_name(std::move(name)), m_start(start), m_end(end),
23
+ m_enum_type(nullptr ) {
22
24
assert (m_start <= m_end && " Start bit must be <= end bit." );
23
25
}
24
26
27
+ RegisterFlags::Field::Field (std::string name, unsigned bit_position)
28
+ : m_name(std::move(name)), m_start(bit_position), m_end(bit_position),
29
+ m_enum_type(nullptr ) {}
30
+
31
+ RegisterFlags::Field::Field (std::string name, unsigned start, unsigned end,
32
+ const FieldEnum *enum_type)
33
+ : m_name(std::move(name)), m_start(start), m_end(end),
34
+ m_enum_type(enum_type) {
35
+ if (m_enum_type) {
36
+ // Check that all values fit into this field. The XML parser will also
37
+ // do this check so at runtime nothing should fail this check.
38
+ // We can also make enums in C++ at compile time, which might fail this
39
+ // check, so we catch them before it makes it into a release.
40
+ uint64_t max_value = GetMaxValue ();
41
+ UNUSED_IF_ASSERT_DISABLED (max_value);
42
+ for (const auto &enumerator : m_enum_type->GetEnumerators ()) {
43
+ UNUSED_IF_ASSERT_DISABLED (enumerator);
44
+ assert (enumerator.m_value <= max_value &&
45
+ " Enumerator value exceeds maximum value for this field" );
46
+ }
47
+ }
48
+ }
49
+
25
50
void RegisterFlags::Field::log (Log *log) const {
26
51
LLDB_LOG (log, " Name: \" {0}\" Start: {1} End: {2}" , m_name.c_str (), m_start,
27
52
m_end);
@@ -53,6 +78,35 @@ unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
53
78
return lhs_start - rhs_end - 1 ;
54
79
}
55
80
81
+ unsigned RegisterFlags::Field::GetSizeInBits (unsigned start, unsigned end) {
82
+ return end - start + 1 ;
83
+ }
84
+
85
+ unsigned RegisterFlags::Field::GetSizeInBits () const {
86
+ return GetSizeInBits (m_start, m_end);
87
+ }
88
+
89
+ uint64_t RegisterFlags::Field::GetMaxValue (unsigned start, unsigned end) {
90
+ uint64_t max = std::numeric_limits<uint64_t >::max ();
91
+ unsigned bits = GetSizeInBits (start, end);
92
+ // If the field is >= 64 bits the shift below would be undefined.
93
+ // We assume the GDB client has discarded any field that would fail this
94
+ // assert, it's only to check information we define directly in C++.
95
+ assert (bits <= 64 && " Cannot handle field with size > 64 bits" );
96
+ if (bits < 64 ) {
97
+ max = ((uint64_t )1 << bits) - 1 ;
98
+ }
99
+ return max;
100
+ }
101
+
102
+ uint64_t RegisterFlags::Field::GetMaxValue () const {
103
+ return GetMaxValue (m_start, m_end);
104
+ }
105
+
106
+ uint64_t RegisterFlags::Field::GetMask () const {
107
+ return GetMaxValue () << m_start;
108
+ }
109
+
56
110
void RegisterFlags::SetFields (const std::vector<Field> &fields) {
57
111
// We expect that the XML processor will discard anything describing flags but
58
112
// with no fields.
@@ -190,6 +244,132 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const {
190
244
return table;
191
245
}
192
246
247
+ // Print enums as:
248
+ // value = name, value2 = name2
249
+ // Subject to the limits of the terminal width.
250
+ static void DumpEnumerators (StreamString &strm, size_t indent,
251
+ size_t current_width, uint32_t max_width,
252
+ const FieldEnum::Enumerators &enumerators) {
253
+ for (auto it = enumerators.cbegin (); it != enumerators.cend (); ++it) {
254
+ StreamString enumerator_strm;
255
+ // The first enumerator of a line doesn't need to be separated.
256
+ if (current_width != indent)
257
+ enumerator_strm << ' ' ;
258
+
259
+ enumerator_strm.Printf (" %" PRIu64 " = %s" , it->m_value , it->m_name .c_str ());
260
+
261
+ // Don't put "," after the last enumerator.
262
+ if (std::next (it) != enumerators.cend ())
263
+ enumerator_strm << " ," ;
264
+
265
+ llvm::StringRef enumerator_string = enumerator_strm.GetString ();
266
+ // If printing the next enumerator would take us over the width, start
267
+ // a new line. However, if we're printing the first enumerator of this
268
+ // line, don't start a new one. Resulting in there being at least one per
269
+ // line.
270
+ //
271
+ // This means for very small widths we get:
272
+ // A: 0 = foo,
273
+ // 1 = bar
274
+ // Instead of:
275
+ // A:
276
+ // 0 = foo,
277
+ // 1 = bar
278
+ if ((current_width + enumerator_string.size () > max_width) &&
279
+ current_width != indent) {
280
+ current_width = indent;
281
+ strm << ' \n ' << std::string (indent, ' ' );
282
+ // We're going to a new line so we don't need a space before the
283
+ // name of the enumerator.
284
+ enumerator_string = enumerator_string.drop_front ();
285
+ }
286
+
287
+ current_width += enumerator_string.size ();
288
+ strm << enumerator_string;
289
+ }
290
+ }
291
+
292
+ std::string RegisterFlags::DumpEnums (uint32_t max_width) const {
293
+ StreamString strm;
294
+ bool printed_enumerators_once = false ;
295
+
296
+ for (const auto &field : m_fields) {
297
+ const FieldEnum *enum_type = field.GetEnum ();
298
+ if (!enum_type)
299
+ continue ;
300
+
301
+ const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators ();
302
+ if (enumerators.empty ())
303
+ continue ;
304
+
305
+ // Break between enumerators of different fields.
306
+ if (printed_enumerators_once)
307
+ strm << " \n\n " ;
308
+ else
309
+ printed_enumerators_once = true ;
310
+
311
+ std::string name_string = field.GetName () + " : " ;
312
+ size_t indent = name_string.size ();
313
+ size_t current_width = indent;
314
+
315
+ strm << name_string;
316
+
317
+ DumpEnumerators (strm, indent, current_width, max_width, enumerators);
318
+ }
319
+
320
+ return strm.GetString ().str ();
321
+ }
322
+
323
+ void RegisterFlags::EnumsToXML (Stream &strm, llvm::StringSet<> &seen) const {
324
+ for (const Field &field : m_fields)
325
+ if (const FieldEnum *enum_type = field.GetEnum ()) {
326
+ const std::string &id = enum_type->GetID ();
327
+ if (!seen.contains (id)) {
328
+ enum_type->ToXML (strm, GetSize ());
329
+ seen.insert (id);
330
+ }
331
+ }
332
+ }
333
+
334
+ void FieldEnum::ToXML (Stream &strm, unsigned size) const {
335
+ // Example XML:
336
+ // <enum id="foo" size="4">
337
+ // <evalue name="bar" value="1"/>
338
+ // </enum>
339
+ // Note that "size" is only emitted for GDB compatibility, LLDB does not need
340
+ // it.
341
+
342
+ strm.Indent ();
343
+ strm << " <enum id=\" " << GetID () << " \" " ;
344
+ // This is the size of the underlying enum type if this were a C type.
345
+ // In other words, the size of the register in bytes.
346
+ strm.Printf (" size=\" %d\" " , size);
347
+
348
+ const Enumerators &enumerators = GetEnumerators ();
349
+ if (enumerators.empty ()) {
350
+ strm << " />\n " ;
351
+ return ;
352
+ }
353
+
354
+ strm << " >\n " ;
355
+ strm.IndentMore ();
356
+ for (const auto &enumerator : enumerators) {
357
+ strm.Indent ();
358
+ enumerator.ToXML (strm);
359
+ strm.PutChar (' \n ' );
360
+ }
361
+ strm.IndentLess ();
362
+ strm.Indent (" </enum>\n " );
363
+ }
364
+
365
+ void FieldEnum::Enumerator::ToXML (Stream &strm) const {
366
+ std::string escaped_name;
367
+ llvm::raw_string_ostream escape_strm (escaped_name);
368
+ llvm::printHTMLEscaped (m_name, escape_strm);
369
+ strm.Printf (" <evalue name=\" %s\" value=\" %" PRIu64 " \" />" ,
370
+ escaped_name.c_str (), m_value);
371
+ }
372
+
193
373
void RegisterFlags::ToXML (Stream &strm) const {
194
374
// Example XML:
195
375
// <flags id="cpsr_flags" size="4">
@@ -214,7 +394,9 @@ void RegisterFlags::ToXML(Stream &strm) const {
214
394
}
215
395
216
396
void RegisterFlags::Field::ToXML (Stream &strm) const {
217
- // Example XML:
397
+ // Example XML with an enum:
398
+ // <field name="correct" start="0" end="0" type="some_enum">
399
+ // Without:
218
400
// <field name="correct" start="0" end="0"/>
219
401
strm.Indent ();
220
402
strm << " <field name=\" " ;
@@ -225,5 +407,17 @@ void RegisterFlags::Field::ToXML(Stream &strm) const {
225
407
strm << escaped_name << " \" " ;
226
408
227
409
strm.Printf (" start=\" %d\" end=\" %d\" " , GetStart (), GetEnd ());
410
+
411
+ if (const FieldEnum *enum_type = GetEnum ())
412
+ strm << " type=\" " << enum_type->GetID () << " \" " ;
413
+
228
414
strm << " />" ;
229
415
}
416
+
417
+ FieldEnum::FieldEnum (std::string id, const Enumerators &enumerators)
418
+ : m_id(id), m_enumerators(enumerators) {
419
+ for (const auto &enumerator : m_enumerators) {
420
+ UNUSED_IF_ASSERT_DISABLED (enumerator);
421
+ assert (enumerator.m_name .size () && " Enumerator name cannot be empty" );
422
+ }
423
+ }
0 commit comments