13#include "llvm/ADT/MapVector.h"
14#include "llvm/ADT/StringExtras.h"
26 assert(
m_start <=
m_end &&
"Start bit must be <= end bit.");
44 for (
const auto &enumerator :
m_enum_type->GetEnumerators()) {
46 assert(enumerator.m_value <= max_value &&
47 "Enumerator value exceeds maximum value for this field");
59 unsigned overlap_end = std::min(
GetEnd(), other.
GetEnd());
60 return overlap_start <= overlap_end;
65 "Cannot get padding distance for overlapping fields.");
66 assert((other < (*
this)) &&
"Expected fields in MSB to LSB order.");
80 return lhs_start - rhs_end - 1;
84 return end - start + 1;
92 uint64_t max = std::numeric_limits<uint64_t>::max();
99 max = ((uint64_t)1 << bits) - 1;
104uint64_t RegisterFlags::Field::GetMaxValue() const {
105 return GetMaxValue(m_start, m_end);
108uint64_t RegisterFlags::Field::GetMask() const {
109 return GetMaxValue() << m_start;
112void RegisterFlags::SetFields(const std::vector<Field> &fields) {
113 // We expect that these are unsorted but do not overlap.
114 // They could fill the register but may have gaps.
115 std::vector<Field> provided_fields = fields;
118 m_fields.reserve(provided_fields.size());
120 // ProcessGDBRemote should have sorted these in descending order already.
121 assert(std::is_sorted(provided_fields.rbegin(), provided_fields.rend()));
123 // Build a new list of fields that includes anonymous (empty name) fields
124 // wherever there is a gap. This will simplify processing later.
125 std::optional<Field> previous_field;
126 unsigned register_msb = (m_size * 8) - 1;
127 for (auto field : provided_fields) {
128 if (previous_field) {
129 unsigned padding = previous_field->PaddingDistance(field);
131 // -1 to end just before the previous field.
132 unsigned end = previous_field->GetStart() - 1;
133 // +1 because if you want to pad 1 bit you want to start and end
135 m_fields.push_back(Field("", field.GetEnd() + 1, end));
138 // This is the first field. Check that it starts at the register's MSB.
139 if (field.GetEnd() != register_msb)
140 m_fields.push_back(Field("", field.GetEnd() + 1, register_msb));
142 m_fields.push_back(field);
143 previous_field = field;
146 // The last field may not extend all the way to bit 0.
147 if (previous_field && previous_field->GetStart() != 0)
148 m_fields.push_back(Field("", 0, previous_field->GetStart() - 1));
151RegisterFlags::RegisterFlags(std::string id, unsigned size,
152 const std::vector<Field> &fields)
153 : m_id(std::move(id)), m_size(size) {
157void RegisterFlags::DumpToLog(Log *log) const {
158 LLDB_LOG(log, "ID: \
"{0}\" Size: {1}",
m_id.c_str(),
m_size);
160 field.DumpToLog(log);
164 unsigned column_width) {
165 unsigned pad = column_width - content.
GetString().size();
169 pad_l = std::string(pad / 2,
' ');
170 pad_r = std::string((pad / 2) + (pad % 2),
' ');
179static void EmitTable(std::string &out, std::array<std::string, 3> &table) {
181 for (std::string &line : table)
184 out += std::accumulate(table.begin() + 1, table.end(), table.front(),
185 [](std::string lhs,
const auto &rhs) {
186 return std::move(lhs) +
"\n" + rhs;
193 std::array<std::string, 3> lines;
194 uint32_t current_width = 0;
198 if (field.GetEnd() == field.GetStart())
199 position.
Printf(
" %d ", field.GetEnd());
201 position.
Printf(
" %d-%d ", field.GetEnd(), field.GetStart());
204 name.
Printf(
" %s ", field.GetName().c_str());
206 unsigned column_width = position.
GetString().size();
207 unsigned name_width = name.
GetString().size();
208 if (name_width > column_width)
209 column_width = name_width;
216 if (current_width && ((current_width + column_width + 1) >= max_width)) {
221 for (std::string &line : lines)
227 lines[0] += aligned_position.
GetString();
229 grid <<
'|' << std::string(column_width,
'-');
235 current_width += column_width + 1;
249 size_t current_width, uint32_t max_width,
251 for (
auto it = enumerators.cbegin(); it != enumerators.cend(); ++it) {
254 if (current_width != indent)
255 enumerator_strm <<
' ';
257 enumerator_strm.
Printf(
"%" PRIu64
" = %s", it->m_value, it->m_name.c_str());
260 if (std::next(it) != enumerators.cend())
261 enumerator_strm <<
",";
263 llvm::StringRef enumerator_string = enumerator_strm.
GetString();
276 if ((current_width + enumerator_string.size() > max_width) &&
277 current_width != indent) {
278 current_width = indent;
279 strm <<
'\n' << std::string(indent,
' ');
282 enumerator_string = enumerator_string.drop_front();
285 current_width += enumerator_string.size();
286 strm << enumerator_string;
293 llvm::MapVector<const FieldEnum *, std::vector<std::string>> enum_uses;
295 if (
const FieldEnum *enum_type = field.GetEnum())
296 enum_uses[enum_type].push_back(field.GetName());
299 bool printed_one_enumerator =
false;
301 for (
const auto &[enum_type, field_names] : enum_uses) {
303 if (printed_one_enumerator)
306 printed_one_enumerator =
true;
308 std::string name_string = llvm::join(field_names,
", ") +
": ";
309 size_t indent = name_string.size();
310 size_t current_width = indent;
315 enum_type->GetEnumerators());
323 if (
const FieldEnum *enum_type = field.GetEnum()) {
324 const std::string &
id = enum_type->GetID();
325 if (!seen.contains(
id)) {
326 enum_type->ToXML(strm,
GetSize());
341 strm <<
"<enum id=\"" <<
GetID() <<
"\" ";
344 strm.
Printf(
"size=\"%d\"", size);
347 if (enumerators.empty()) {
354 for (
const auto &enumerator : enumerators) {
356 enumerator.ToXML(strm);
364 std::string escaped_name;
365 llvm::raw_string_ostream escape_strm(escaped_name);
366 llvm::printHTMLEscaped(
m_name, escape_strm);
367 strm.
Printf(
"<evalue name=\"%s\" value=\"%" PRIu64
"\"/>",
368 escaped_name.c_str(),
m_value);
378 enumerator.DumpToLog(log);
387 strm <<
"<flags id=\"" <<
GetID() <<
"\" ";
392 if (field.GetName().empty())
401 strm.
Indent(
"</flags>\n");
410 strm <<
"<field name=\"";
412 std::string escaped_name;
413 llvm::raw_string_ostream escape_strm(escaped_name);
414 llvm::printHTMLEscaped(
GetName(), escape_strm);
415 strm << escaped_name <<
"\" ";
420 strm <<
" type=\"" << enum_type->GetID() <<
"\"";
429 assert(enumerator.m_name.size() &&
"Enumerator name cannot be empty");
static bool Overlaps(const Entry *region_one, const Entry *region_two)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
static void DumpEnumerators(StreamString &strm, size_t indent, size_t current_width, uint32_t max_width, const FieldEnum::Enumerators &enumerators)
static StreamString FormatCell(const StreamString &content, unsigned column_width)
static void EmitTable(std::string &out, std::array< std::string, 3 > &table)
static llvm::StringRef GetName(XcodeSDK::Type type)
Enumerators m_enumerators
FieldEnum(std::string id, const Enumerators &enumerators)
std::vector< Enumerator > Enumerators
const Enumerators & GetEnumerators() const
void DumpToLog(Log *log) const
void ToXML(Stream &strm, unsigned size) const
bool Overlaps(const Field &other) const
const FieldEnum * m_enum_type
unsigned PaddingDistance(const Field &other) const
Return the number of bits between this field and the other, that are not covered by either field.
const FieldEnum * GetEnum() const
Field(std::string name, unsigned start, unsigned end)
Where start is the least significant bit and end is the most significant bit.
uint64_t GetMaxValue() const
The maximum unsigned value that could be contained in this field.
unsigned GetStart() const
void DumpToLog(Log *log) const
unsigned GetSizeInBits() const
Get size of the field in bits. Will always be at least 1.
unsigned m_start
Start/end bit positions.
void ToXML(Stream &strm) const
Output XML that describes this field, to be inserted into a target XML file.
std::vector< Field > m_fields
std::string DumpEnums(uint32_t max_width) const
Make a string where each line contains the name of a field that has enum values, and lists what those...
const unsigned m_size
Size in bytes.
void EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const
Enum types must be defined before use, and GDBRemoteCommunicationServerLLGS view of the register type...
const std::string & GetID() const
void ToXML(Stream &strm) const
Output XML that describes this set of flags.
std::string AsTable(uint32_t max_width) const
Produce a text table showing the layout of all the fields.
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
void IndentMore(unsigned amount=2)
Increment the current indentation level.
#define UNUSED_IF_ASSERT_DISABLED(x)
A class that represents a running process on the host machine.
static uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
void ToXML(Stream &strm) const
void DumpToLog(Log *log) const