1212
1313#include " llvm/ADT/StringExtras.h"
1414
15+ #include < limits>
1516#include < numeric>
1617#include < optional>
1718
1819using namespace lldb_private ;
1920
2021RegisterFlags::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 ) {
2224 assert (m_start <= m_end && " Start bit must be <= end bit." );
2325}
2426
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+
2550void RegisterFlags::Field::log (Log *log) const {
2651 LLDB_LOG (log, " Name: \" {0}\" Start: {1} End: {2}" , m_name.c_str (), m_start,
2752 m_end);
@@ -53,6 +78,35 @@ unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
5378 return lhs_start - rhs_end - 1 ;
5479}
5580
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+
56110void RegisterFlags::SetFields (const std::vector<Field> &fields) {
57111 // We expect that the XML processor will discard anything describing flags but
58112 // with no fields.
@@ -190,6 +244,132 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const {
190244 return table;
191245}
192246
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+
193373void RegisterFlags::ToXML (Stream &strm) const {
194374 // Example XML:
195375 // <flags id="cpsr_flags" size="4">
@@ -214,7 +394,9 @@ void RegisterFlags::ToXML(Stream &strm) const {
214394}
215395
216396void 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:
218400 // <field name="correct" start="0" end="0"/>
219401 strm.Indent ();
220402 strm << " <field name=\" " ;
@@ -225,5 +407,17 @@ void RegisterFlags::Field::ToXML(Stream &strm) const {
225407 strm << escaped_name << " \" " ;
226408
227409 strm.Printf (" start=\" %d\" end=\" %d\" " , GetStart (), GetEnd ());
410+
411+ if (const FieldEnum *enum_type = GetEnum ())
412+ strm << " type=\" " << enum_type->GetID () << " \" " ;
413+
228414 strm << " />" ;
229415}
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