xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/RegisterFlags.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- RegisterFlags.cpp -------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "lldb/Target/RegisterFlags.h"
105f757f3fSDimitry Andric #include "lldb/Utility/Log.h"
1106c3fb27SDimitry Andric #include "lldb/Utility/StreamString.h"
1206c3fb27SDimitry Andric 
135f757f3fSDimitry Andric #include "llvm/ADT/StringExtras.h"
145f757f3fSDimitry Andric 
15*0fca6ea1SDimitry Andric #include <limits>
1606c3fb27SDimitry Andric #include <numeric>
1706c3fb27SDimitry Andric #include <optional>
1806c3fb27SDimitry Andric 
1906c3fb27SDimitry Andric using namespace lldb_private;
2006c3fb27SDimitry Andric 
215f757f3fSDimitry Andric RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end)
22*0fca6ea1SDimitry Andric     : m_name(std::move(name)), m_start(start), m_end(end),
23*0fca6ea1SDimitry Andric       m_enum_type(nullptr) {
245f757f3fSDimitry Andric   assert(m_start <= m_end && "Start bit must be <= end bit.");
255f757f3fSDimitry Andric }
265f757f3fSDimitry Andric 
27*0fca6ea1SDimitry Andric RegisterFlags::Field::Field(std::string name, unsigned bit_position)
28*0fca6ea1SDimitry Andric     : m_name(std::move(name)), m_start(bit_position), m_end(bit_position),
29*0fca6ea1SDimitry Andric       m_enum_type(nullptr) {}
30*0fca6ea1SDimitry Andric 
31*0fca6ea1SDimitry Andric RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end,
32*0fca6ea1SDimitry Andric                             const FieldEnum *enum_type)
33*0fca6ea1SDimitry Andric     : m_name(std::move(name)), m_start(start), m_end(end),
34*0fca6ea1SDimitry Andric       m_enum_type(enum_type) {
35*0fca6ea1SDimitry Andric   if (m_enum_type) {
36*0fca6ea1SDimitry Andric     // Check that all values fit into this field. The XML parser will also
37*0fca6ea1SDimitry Andric     // do this check so at runtime nothing should fail this check.
38*0fca6ea1SDimitry Andric     // We can also make enums in C++ at compile time, which might fail this
39*0fca6ea1SDimitry Andric     // check, so we catch them before it makes it into a release.
40*0fca6ea1SDimitry Andric     uint64_t max_value = GetMaxValue();
41*0fca6ea1SDimitry Andric     UNUSED_IF_ASSERT_DISABLED(max_value);
42*0fca6ea1SDimitry Andric     for (const auto &enumerator : m_enum_type->GetEnumerators()) {
43*0fca6ea1SDimitry Andric       UNUSED_IF_ASSERT_DISABLED(enumerator);
44*0fca6ea1SDimitry Andric       assert(enumerator.m_value <= max_value &&
45*0fca6ea1SDimitry Andric              "Enumerator value exceeds maximum value for this field");
46*0fca6ea1SDimitry Andric     }
47*0fca6ea1SDimitry Andric   }
48*0fca6ea1SDimitry Andric }
49*0fca6ea1SDimitry Andric 
50*0fca6ea1SDimitry Andric void RegisterFlags::Field::DumpToLog(Log *log) const {
5106c3fb27SDimitry Andric   LLDB_LOG(log, "  Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start,
5206c3fb27SDimitry Andric            m_end);
5306c3fb27SDimitry Andric }
5406c3fb27SDimitry Andric 
5506c3fb27SDimitry Andric bool RegisterFlags::Field::Overlaps(const Field &other) const {
5606c3fb27SDimitry Andric   unsigned overlap_start = std::max(GetStart(), other.GetStart());
5706c3fb27SDimitry Andric   unsigned overlap_end = std::min(GetEnd(), other.GetEnd());
5806c3fb27SDimitry Andric   return overlap_start <= overlap_end;
5906c3fb27SDimitry Andric }
6006c3fb27SDimitry Andric 
6106c3fb27SDimitry Andric unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
6206c3fb27SDimitry Andric   assert(!Overlaps(other) &&
6306c3fb27SDimitry Andric          "Cannot get padding distance for overlapping fields.");
6406c3fb27SDimitry Andric   assert((other < (*this)) && "Expected fields in MSB to LSB order.");
6506c3fb27SDimitry Andric 
6606c3fb27SDimitry Andric   // If they don't overlap they are either next to each other or separated
6706c3fb27SDimitry Andric   // by some number of bits.
6806c3fb27SDimitry Andric 
6906c3fb27SDimitry Andric   // Where left will be the MSB and right will be the LSB.
7006c3fb27SDimitry Andric   unsigned lhs_start = GetStart();
7106c3fb27SDimitry Andric   unsigned rhs_end = other.GetStart() + other.GetSizeInBits() - 1;
7206c3fb27SDimitry Andric 
7306c3fb27SDimitry Andric   if (*this < other) {
7406c3fb27SDimitry Andric     lhs_start = other.GetStart();
7506c3fb27SDimitry Andric     rhs_end = GetStart() + GetSizeInBits() - 1;
7606c3fb27SDimitry Andric   }
7706c3fb27SDimitry Andric 
7806c3fb27SDimitry Andric   return lhs_start - rhs_end - 1;
7906c3fb27SDimitry Andric }
8006c3fb27SDimitry Andric 
81*0fca6ea1SDimitry Andric unsigned RegisterFlags::Field::GetSizeInBits(unsigned start, unsigned end) {
82*0fca6ea1SDimitry Andric   return end - start + 1;
83*0fca6ea1SDimitry Andric }
8406c3fb27SDimitry Andric 
85*0fca6ea1SDimitry Andric unsigned RegisterFlags::Field::GetSizeInBits() const {
86*0fca6ea1SDimitry Andric   return GetSizeInBits(m_start, m_end);
87*0fca6ea1SDimitry Andric }
88*0fca6ea1SDimitry Andric 
89*0fca6ea1SDimitry Andric uint64_t RegisterFlags::Field::GetMaxValue(unsigned start, unsigned end) {
90*0fca6ea1SDimitry Andric   uint64_t max = std::numeric_limits<uint64_t>::max();
91*0fca6ea1SDimitry Andric   unsigned bits = GetSizeInBits(start, end);
92*0fca6ea1SDimitry Andric   // If the field is >= 64 bits the shift below would be undefined.
93*0fca6ea1SDimitry Andric   // We assume the GDB client has discarded any field that would fail this
94*0fca6ea1SDimitry Andric   // assert, it's only to check information we define directly in C++.
95*0fca6ea1SDimitry Andric   assert(bits <= 64 && "Cannot handle field with size > 64 bits");
96*0fca6ea1SDimitry Andric   if (bits < 64) {
97*0fca6ea1SDimitry Andric     max = ((uint64_t)1 << bits) - 1;
98*0fca6ea1SDimitry Andric   }
99*0fca6ea1SDimitry Andric   return max;
100*0fca6ea1SDimitry Andric }
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric uint64_t RegisterFlags::Field::GetMaxValue() const {
103*0fca6ea1SDimitry Andric   return GetMaxValue(m_start, m_end);
104*0fca6ea1SDimitry Andric }
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric uint64_t RegisterFlags::Field::GetMask() const {
107*0fca6ea1SDimitry Andric   return GetMaxValue() << m_start;
108*0fca6ea1SDimitry Andric }
109*0fca6ea1SDimitry Andric 
110*0fca6ea1SDimitry Andric void RegisterFlags::SetFields(const std::vector<Field> &fields) {
11106c3fb27SDimitry Andric   // We expect that these are unsorted but do not overlap.
11206c3fb27SDimitry Andric   // They could fill the register but may have gaps.
11306c3fb27SDimitry Andric   std::vector<Field> provided_fields = fields;
1145f757f3fSDimitry Andric 
1155f757f3fSDimitry Andric   m_fields.clear();
11606c3fb27SDimitry Andric   m_fields.reserve(provided_fields.size());
11706c3fb27SDimitry Andric 
11806c3fb27SDimitry Andric   // ProcessGDBRemote should have sorted these in descending order already.
11906c3fb27SDimitry Andric   assert(std::is_sorted(provided_fields.rbegin(), provided_fields.rend()));
12006c3fb27SDimitry Andric 
12106c3fb27SDimitry Andric   // Build a new list of fields that includes anonymous (empty name) fields
12206c3fb27SDimitry Andric   // wherever there is a gap. This will simplify processing later.
12306c3fb27SDimitry Andric   std::optional<Field> previous_field;
1245f757f3fSDimitry Andric   unsigned register_msb = (m_size * 8) - 1;
12506c3fb27SDimitry Andric   for (auto field : provided_fields) {
12606c3fb27SDimitry Andric     if (previous_field) {
12706c3fb27SDimitry Andric       unsigned padding = previous_field->PaddingDistance(field);
12806c3fb27SDimitry Andric       if (padding) {
12906c3fb27SDimitry Andric         // -1 to end just before the previous field.
13006c3fb27SDimitry Andric         unsigned end = previous_field->GetStart() - 1;
13106c3fb27SDimitry Andric         // +1 because if you want to pad 1 bit you want to start and end
13206c3fb27SDimitry Andric         // on the same bit.
13306c3fb27SDimitry Andric         m_fields.push_back(Field("", field.GetEnd() + 1, end));
13406c3fb27SDimitry Andric       }
13506c3fb27SDimitry Andric     } else {
13606c3fb27SDimitry Andric       // This is the first field. Check that it starts at the register's MSB.
13706c3fb27SDimitry Andric       if (field.GetEnd() != register_msb)
13806c3fb27SDimitry Andric         m_fields.push_back(Field("", field.GetEnd() + 1, register_msb));
13906c3fb27SDimitry Andric     }
14006c3fb27SDimitry Andric     m_fields.push_back(field);
14106c3fb27SDimitry Andric     previous_field = field;
14206c3fb27SDimitry Andric   }
14306c3fb27SDimitry Andric 
14406c3fb27SDimitry Andric   // The last field may not extend all the way to bit 0.
14506c3fb27SDimitry Andric   if (previous_field && previous_field->GetStart() != 0)
14606c3fb27SDimitry Andric     m_fields.push_back(Field("", 0, previous_field->GetStart() - 1));
14706c3fb27SDimitry Andric }
14806c3fb27SDimitry Andric 
1495f757f3fSDimitry Andric RegisterFlags::RegisterFlags(std::string id, unsigned size,
1505f757f3fSDimitry Andric                              const std::vector<Field> &fields)
1515f757f3fSDimitry Andric     : m_id(std::move(id)), m_size(size) {
1525f757f3fSDimitry Andric   SetFields(fields);
1535f757f3fSDimitry Andric }
1545f757f3fSDimitry Andric 
155*0fca6ea1SDimitry Andric void RegisterFlags::DumpToLog(Log *log) const {
15606c3fb27SDimitry Andric   LLDB_LOG(log, "ID: \"{0}\" Size: {1}", m_id.c_str(), m_size);
15706c3fb27SDimitry Andric   for (const Field &field : m_fields)
158*0fca6ea1SDimitry Andric     field.DumpToLog(log);
15906c3fb27SDimitry Andric }
16006c3fb27SDimitry Andric 
16106c3fb27SDimitry Andric static StreamString FormatCell(const StreamString &content,
16206c3fb27SDimitry Andric                                unsigned column_width) {
16306c3fb27SDimitry Andric   unsigned pad = column_width - content.GetString().size();
16406c3fb27SDimitry Andric   std::string pad_l;
16506c3fb27SDimitry Andric   std::string pad_r;
16606c3fb27SDimitry Andric   if (pad) {
16706c3fb27SDimitry Andric     pad_l = std::string(pad / 2, ' ');
16806c3fb27SDimitry Andric     pad_r = std::string((pad / 2) + (pad % 2), ' ');
16906c3fb27SDimitry Andric   }
17006c3fb27SDimitry Andric 
17106c3fb27SDimitry Andric   StreamString aligned;
17206c3fb27SDimitry Andric   aligned.Printf("|%s%s%s", pad_l.c_str(), content.GetString().data(),
17306c3fb27SDimitry Andric                  pad_r.c_str());
17406c3fb27SDimitry Andric   return aligned;
17506c3fb27SDimitry Andric }
17606c3fb27SDimitry Andric 
17706c3fb27SDimitry Andric static void EmitTable(std::string &out, std::array<std::string, 3> &table) {
17806c3fb27SDimitry Andric   // Close the table.
17906c3fb27SDimitry Andric   for (std::string &line : table)
18006c3fb27SDimitry Andric     line += '|';
18106c3fb27SDimitry Andric 
18206c3fb27SDimitry Andric   out += std::accumulate(table.begin() + 1, table.end(), table.front(),
18306c3fb27SDimitry Andric                          [](std::string lhs, const auto &rhs) {
18406c3fb27SDimitry Andric                            return std::move(lhs) + "\n" + rhs;
18506c3fb27SDimitry Andric                          });
18606c3fb27SDimitry Andric }
18706c3fb27SDimitry Andric 
18806c3fb27SDimitry Andric std::string RegisterFlags::AsTable(uint32_t max_width) const {
18906c3fb27SDimitry Andric   std::string table;
19006c3fb27SDimitry Andric   // position / gridline / name
19106c3fb27SDimitry Andric   std::array<std::string, 3> lines;
19206c3fb27SDimitry Andric   uint32_t current_width = 0;
19306c3fb27SDimitry Andric 
19406c3fb27SDimitry Andric   for (const RegisterFlags::Field &field : m_fields) {
19506c3fb27SDimitry Andric     StreamString position;
19606c3fb27SDimitry Andric     if (field.GetEnd() == field.GetStart())
19706c3fb27SDimitry Andric       position.Printf(" %d ", field.GetEnd());
19806c3fb27SDimitry Andric     else
19906c3fb27SDimitry Andric       position.Printf(" %d-%d ", field.GetEnd(), field.GetStart());
20006c3fb27SDimitry Andric 
20106c3fb27SDimitry Andric     StreamString name;
20206c3fb27SDimitry Andric     name.Printf(" %s ", field.GetName().c_str());
20306c3fb27SDimitry Andric 
20406c3fb27SDimitry Andric     unsigned column_width = position.GetString().size();
20506c3fb27SDimitry Andric     unsigned name_width = name.GetString().size();
20606c3fb27SDimitry Andric     if (name_width > column_width)
20706c3fb27SDimitry Andric       column_width = name_width;
20806c3fb27SDimitry Andric 
20906c3fb27SDimitry Andric     // If the next column would overflow and we have already formatted at least
21006c3fb27SDimitry Andric     // one column, put out what we have and move to a new table on the next line
21106c3fb27SDimitry Andric     // (+1 here because we need to cap the ends with '|'). If this is the first
21206c3fb27SDimitry Andric     // column, just let it overflow and we'll wrap next time around. There's not
21306c3fb27SDimitry Andric     // much we can do with a very small terminal.
21406c3fb27SDimitry Andric     if (current_width && ((current_width + column_width + 1) >= max_width)) {
21506c3fb27SDimitry Andric       EmitTable(table, lines);
21606c3fb27SDimitry Andric       // Blank line between each.
21706c3fb27SDimitry Andric       table += "\n\n";
21806c3fb27SDimitry Andric 
21906c3fb27SDimitry Andric       for (std::string &line : lines)
22006c3fb27SDimitry Andric         line.clear();
22106c3fb27SDimitry Andric       current_width = 0;
22206c3fb27SDimitry Andric     }
22306c3fb27SDimitry Andric 
22406c3fb27SDimitry Andric     StreamString aligned_position = FormatCell(position, column_width);
22506c3fb27SDimitry Andric     lines[0] += aligned_position.GetString();
22606c3fb27SDimitry Andric     StreamString grid;
22706c3fb27SDimitry Andric     grid << '|' << std::string(column_width, '-');
22806c3fb27SDimitry Andric     lines[1] += grid.GetString();
22906c3fb27SDimitry Andric     StreamString aligned_name = FormatCell(name, column_width);
23006c3fb27SDimitry Andric     lines[2] += aligned_name.GetString();
23106c3fb27SDimitry Andric 
23206c3fb27SDimitry Andric     // +1 for the left side '|'.
23306c3fb27SDimitry Andric     current_width += column_width + 1;
23406c3fb27SDimitry Andric   }
23506c3fb27SDimitry Andric 
23606c3fb27SDimitry Andric   // If we didn't overflow and still have table to print out.
23706c3fb27SDimitry Andric   if (lines[0].size())
23806c3fb27SDimitry Andric     EmitTable(table, lines);
23906c3fb27SDimitry Andric 
24006c3fb27SDimitry Andric   return table;
24106c3fb27SDimitry Andric }
2425f757f3fSDimitry Andric 
243*0fca6ea1SDimitry Andric // Print enums as:
244*0fca6ea1SDimitry Andric // value = name, value2 = name2
245*0fca6ea1SDimitry Andric // Subject to the limits of the terminal width.
246*0fca6ea1SDimitry Andric static void DumpEnumerators(StreamString &strm, size_t indent,
247*0fca6ea1SDimitry Andric                             size_t current_width, uint32_t max_width,
248*0fca6ea1SDimitry Andric                             const FieldEnum::Enumerators &enumerators) {
249*0fca6ea1SDimitry Andric   for (auto it = enumerators.cbegin(); it != enumerators.cend(); ++it) {
250*0fca6ea1SDimitry Andric     StreamString enumerator_strm;
251*0fca6ea1SDimitry Andric     // The first enumerator of a line doesn't need to be separated.
252*0fca6ea1SDimitry Andric     if (current_width != indent)
253*0fca6ea1SDimitry Andric       enumerator_strm << ' ';
254*0fca6ea1SDimitry Andric 
255*0fca6ea1SDimitry Andric     enumerator_strm.Printf("%" PRIu64 " = %s", it->m_value, it->m_name.c_str());
256*0fca6ea1SDimitry Andric 
257*0fca6ea1SDimitry Andric     // Don't put "," after the last enumerator.
258*0fca6ea1SDimitry Andric     if (std::next(it) != enumerators.cend())
259*0fca6ea1SDimitry Andric       enumerator_strm << ",";
260*0fca6ea1SDimitry Andric 
261*0fca6ea1SDimitry Andric     llvm::StringRef enumerator_string = enumerator_strm.GetString();
262*0fca6ea1SDimitry Andric     // If printing the next enumerator would take us over the width, start
263*0fca6ea1SDimitry Andric     // a new line. However, if we're printing the first enumerator of this
264*0fca6ea1SDimitry Andric     // line, don't start a new one. Resulting in there being at least one per
265*0fca6ea1SDimitry Andric     // line.
266*0fca6ea1SDimitry Andric     //
267*0fca6ea1SDimitry Andric     // This means for very small widths we get:
268*0fca6ea1SDimitry Andric     // A: 0 = foo,
269*0fca6ea1SDimitry Andric     //    1 = bar
270*0fca6ea1SDimitry Andric     // Instead of:
271*0fca6ea1SDimitry Andric     // A:
272*0fca6ea1SDimitry Andric     //    0 = foo,
273*0fca6ea1SDimitry Andric     //    1 = bar
274*0fca6ea1SDimitry Andric     if ((current_width + enumerator_string.size() > max_width) &&
275*0fca6ea1SDimitry Andric         current_width != indent) {
276*0fca6ea1SDimitry Andric       current_width = indent;
277*0fca6ea1SDimitry Andric       strm << '\n' << std::string(indent, ' ');
278*0fca6ea1SDimitry Andric       // We're going to a new line so we don't need a space before the
279*0fca6ea1SDimitry Andric       // name of the enumerator.
280*0fca6ea1SDimitry Andric       enumerator_string = enumerator_string.drop_front();
281*0fca6ea1SDimitry Andric     }
282*0fca6ea1SDimitry Andric 
283*0fca6ea1SDimitry Andric     current_width += enumerator_string.size();
284*0fca6ea1SDimitry Andric     strm << enumerator_string;
285*0fca6ea1SDimitry Andric   }
286*0fca6ea1SDimitry Andric }
287*0fca6ea1SDimitry Andric 
288*0fca6ea1SDimitry Andric std::string RegisterFlags::DumpEnums(uint32_t max_width) const {
289*0fca6ea1SDimitry Andric   StreamString strm;
290*0fca6ea1SDimitry Andric   bool printed_enumerators_once = false;
291*0fca6ea1SDimitry Andric 
292*0fca6ea1SDimitry Andric   for (const auto &field : m_fields) {
293*0fca6ea1SDimitry Andric     const FieldEnum *enum_type = field.GetEnum();
294*0fca6ea1SDimitry Andric     if (!enum_type)
295*0fca6ea1SDimitry Andric       continue;
296*0fca6ea1SDimitry Andric 
297*0fca6ea1SDimitry Andric     const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators();
298*0fca6ea1SDimitry Andric     if (enumerators.empty())
299*0fca6ea1SDimitry Andric       continue;
300*0fca6ea1SDimitry Andric 
301*0fca6ea1SDimitry Andric     // Break between enumerators of different fields.
302*0fca6ea1SDimitry Andric     if (printed_enumerators_once)
303*0fca6ea1SDimitry Andric       strm << "\n\n";
304*0fca6ea1SDimitry Andric     else
305*0fca6ea1SDimitry Andric       printed_enumerators_once = true;
306*0fca6ea1SDimitry Andric 
307*0fca6ea1SDimitry Andric     std::string name_string = field.GetName() + ": ";
308*0fca6ea1SDimitry Andric     size_t indent = name_string.size();
309*0fca6ea1SDimitry Andric     size_t current_width = indent;
310*0fca6ea1SDimitry Andric 
311*0fca6ea1SDimitry Andric     strm << name_string;
312*0fca6ea1SDimitry Andric 
313*0fca6ea1SDimitry Andric     DumpEnumerators(strm, indent, current_width, max_width, enumerators);
314*0fca6ea1SDimitry Andric   }
315*0fca6ea1SDimitry Andric 
316*0fca6ea1SDimitry Andric   return strm.GetString().str();
317*0fca6ea1SDimitry Andric }
318*0fca6ea1SDimitry Andric 
319*0fca6ea1SDimitry Andric void RegisterFlags::EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const {
320*0fca6ea1SDimitry Andric   for (const Field &field : m_fields)
321*0fca6ea1SDimitry Andric     if (const FieldEnum *enum_type = field.GetEnum()) {
322*0fca6ea1SDimitry Andric       const std::string &id = enum_type->GetID();
323*0fca6ea1SDimitry Andric       if (!seen.contains(id)) {
324*0fca6ea1SDimitry Andric         enum_type->ToXML(strm, GetSize());
325*0fca6ea1SDimitry Andric         seen.insert(id);
326*0fca6ea1SDimitry Andric       }
327*0fca6ea1SDimitry Andric     }
328*0fca6ea1SDimitry Andric }
329*0fca6ea1SDimitry Andric 
330*0fca6ea1SDimitry Andric void FieldEnum::ToXML(Stream &strm, unsigned size) const {
331*0fca6ea1SDimitry Andric   // Example XML:
332*0fca6ea1SDimitry Andric   // <enum id="foo" size="4">
333*0fca6ea1SDimitry Andric   //  <evalue name="bar" value="1"/>
334*0fca6ea1SDimitry Andric   // </enum>
335*0fca6ea1SDimitry Andric   // Note that "size" is only emitted for GDB compatibility, LLDB does not need
336*0fca6ea1SDimitry Andric   // it.
337*0fca6ea1SDimitry Andric 
338*0fca6ea1SDimitry Andric   strm.Indent();
339*0fca6ea1SDimitry Andric   strm << "<enum id=\"" << GetID() << "\" ";
340*0fca6ea1SDimitry Andric   // This is the size of the underlying enum type if this were a C type.
341*0fca6ea1SDimitry Andric   // In other words, the size of the register in bytes.
342*0fca6ea1SDimitry Andric   strm.Printf("size=\"%d\"", size);
343*0fca6ea1SDimitry Andric 
344*0fca6ea1SDimitry Andric   const Enumerators &enumerators = GetEnumerators();
345*0fca6ea1SDimitry Andric   if (enumerators.empty()) {
346*0fca6ea1SDimitry Andric     strm << "/>\n";
347*0fca6ea1SDimitry Andric     return;
348*0fca6ea1SDimitry Andric   }
349*0fca6ea1SDimitry Andric 
350*0fca6ea1SDimitry Andric   strm << ">\n";
351*0fca6ea1SDimitry Andric   strm.IndentMore();
352*0fca6ea1SDimitry Andric   for (const auto &enumerator : enumerators) {
353*0fca6ea1SDimitry Andric     strm.Indent();
354*0fca6ea1SDimitry Andric     enumerator.ToXML(strm);
355*0fca6ea1SDimitry Andric     strm.PutChar('\n');
356*0fca6ea1SDimitry Andric   }
357*0fca6ea1SDimitry Andric   strm.IndentLess();
358*0fca6ea1SDimitry Andric   strm.Indent("</enum>\n");
359*0fca6ea1SDimitry Andric }
360*0fca6ea1SDimitry Andric 
361*0fca6ea1SDimitry Andric void FieldEnum::Enumerator::ToXML(Stream &strm) const {
362*0fca6ea1SDimitry Andric   std::string escaped_name;
363*0fca6ea1SDimitry Andric   llvm::raw_string_ostream escape_strm(escaped_name);
364*0fca6ea1SDimitry Andric   llvm::printHTMLEscaped(m_name, escape_strm);
365*0fca6ea1SDimitry Andric   strm.Printf("<evalue name=\"%s\" value=\"%" PRIu64 "\"/>",
366*0fca6ea1SDimitry Andric               escaped_name.c_str(), m_value);
367*0fca6ea1SDimitry Andric }
368*0fca6ea1SDimitry Andric 
369*0fca6ea1SDimitry Andric void FieldEnum::Enumerator::DumpToLog(Log *log) const {
370*0fca6ea1SDimitry Andric   LLDB_LOG(log, "  Name: \"{0}\" Value: {1}", m_name.c_str(), m_value);
371*0fca6ea1SDimitry Andric }
372*0fca6ea1SDimitry Andric 
373*0fca6ea1SDimitry Andric void FieldEnum::DumpToLog(Log *log) const {
374*0fca6ea1SDimitry Andric   LLDB_LOG(log, "ID: \"{0}\"", m_id.c_str());
375*0fca6ea1SDimitry Andric   for (const auto &enumerator : GetEnumerators())
376*0fca6ea1SDimitry Andric     enumerator.DumpToLog(log);
377*0fca6ea1SDimitry Andric }
378*0fca6ea1SDimitry Andric 
379*0fca6ea1SDimitry Andric void RegisterFlags::ToXML(Stream &strm) const {
3805f757f3fSDimitry Andric   // Example XML:
3815f757f3fSDimitry Andric   // <flags id="cpsr_flags" size="4">
3825f757f3fSDimitry Andric   //   <field name="incorrect" start="0" end="0"/>
3835f757f3fSDimitry Andric   // </flags>
3845f757f3fSDimitry Andric   strm.Indent();
3855f757f3fSDimitry Andric   strm << "<flags id=\"" << GetID() << "\" ";
3865f757f3fSDimitry Andric   strm.Printf("size=\"%d\"", GetSize());
3875f757f3fSDimitry Andric   strm << ">";
3885f757f3fSDimitry Andric   for (const Field &field : m_fields) {
3895f757f3fSDimitry Andric     // Skip padding fields.
3905f757f3fSDimitry Andric     if (field.GetName().empty())
3915f757f3fSDimitry Andric       continue;
3925f757f3fSDimitry Andric 
3935f757f3fSDimitry Andric     strm << "\n";
3945f757f3fSDimitry Andric     strm.IndentMore();
3955f757f3fSDimitry Andric     field.ToXML(strm);
3965f757f3fSDimitry Andric     strm.IndentLess();
3975f757f3fSDimitry Andric   }
3985f757f3fSDimitry Andric   strm.PutChar('\n');
3995f757f3fSDimitry Andric   strm.Indent("</flags>\n");
4005f757f3fSDimitry Andric }
4015f757f3fSDimitry Andric 
402*0fca6ea1SDimitry Andric void RegisterFlags::Field::ToXML(Stream &strm) const {
403*0fca6ea1SDimitry Andric   // Example XML with an enum:
404*0fca6ea1SDimitry Andric   // <field name="correct" start="0" end="0" type="some_enum">
405*0fca6ea1SDimitry Andric   // Without:
4065f757f3fSDimitry Andric   // <field name="correct" start="0" end="0"/>
4075f757f3fSDimitry Andric   strm.Indent();
4085f757f3fSDimitry Andric   strm << "<field name=\"";
4095f757f3fSDimitry Andric 
4105f757f3fSDimitry Andric   std::string escaped_name;
4115f757f3fSDimitry Andric   llvm::raw_string_ostream escape_strm(escaped_name);
4125f757f3fSDimitry Andric   llvm::printHTMLEscaped(GetName(), escape_strm);
4135f757f3fSDimitry Andric   strm << escaped_name << "\" ";
4145f757f3fSDimitry Andric 
4155f757f3fSDimitry Andric   strm.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd());
416*0fca6ea1SDimitry Andric 
417*0fca6ea1SDimitry Andric   if (const FieldEnum *enum_type = GetEnum())
418*0fca6ea1SDimitry Andric     strm << " type=\"" << enum_type->GetID() << "\"";
419*0fca6ea1SDimitry Andric 
4205f757f3fSDimitry Andric   strm << "/>";
4215f757f3fSDimitry Andric }
422*0fca6ea1SDimitry Andric 
423*0fca6ea1SDimitry Andric FieldEnum::FieldEnum(std::string id, const Enumerators &enumerators)
424*0fca6ea1SDimitry Andric     : m_id(id), m_enumerators(enumerators) {
425*0fca6ea1SDimitry Andric   for (const auto &enumerator : m_enumerators) {
426*0fca6ea1SDimitry Andric     UNUSED_IF_ASSERT_DISABLED(enumerator);
427*0fca6ea1SDimitry Andric     assert(enumerator.m_name.size() && "Enumerator name cannot be empty");
428*0fca6ea1SDimitry Andric   }
429*0fca6ea1SDimitry Andric }