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 }