LLDB mainline
RegisterFlags.cpp
Go to the documentation of this file.
1//===-- RegisterFlags.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "lldb/Utility/Log.h"
12
13#include "llvm/ADT/StringExtras.h"
14
15#include <numeric>
16#include <optional>
17
18using namespace lldb_private;
19
20RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end)
21 : m_name(std::move(name)), m_start(start), m_end(end) {
22 assert(m_start <= m_end && "Start bit must be <= end bit.");
23}
24
26 LLDB_LOG(log, " Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start,
27 m_end);
28}
29
30bool RegisterFlags::Field::Overlaps(const Field &other) const {
31 unsigned overlap_start = std::max(GetStart(), other.GetStart());
32 unsigned overlap_end = std::min(GetEnd(), other.GetEnd());
33 return overlap_start <= overlap_end;
34}
35
36unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
37 assert(!Overlaps(other) &&
38 "Cannot get padding distance for overlapping fields.");
39 assert((other < (*this)) && "Expected fields in MSB to LSB order.");
40
41 // If they don't overlap they are either next to each other or separated
42 // by some number of bits.
43
44 // Where left will be the MSB and right will be the LSB.
45 unsigned lhs_start = GetStart();
46 unsigned rhs_end = other.GetStart() + other.GetSizeInBits() - 1;
47
48 if (*this < other) {
49 lhs_start = other.GetStart();
50 rhs_end = GetStart() + GetSizeInBits() - 1;
51 }
52
53 return lhs_start - rhs_end - 1;
54}
55
56void RegisterFlags::SetFields(const std::vector<Field> &fields) {
57 // We expect that the XML processor will discard anything describing flags but
58 // with no fields.
59 assert(fields.size() && "Some fields must be provided.");
60
61 // We expect that these are unsorted but do not overlap.
62 // They could fill the register but may have gaps.
63 std::vector<Field> provided_fields = fields;
64
65 m_fields.clear();
66 m_fields.reserve(provided_fields.size());
67
68 // ProcessGDBRemote should have sorted these in descending order already.
69 assert(std::is_sorted(provided_fields.rbegin(), provided_fields.rend()));
70
71 // Build a new list of fields that includes anonymous (empty name) fields
72 // wherever there is a gap. This will simplify processing later.
73 std::optional<Field> previous_field;
74 unsigned register_msb = (m_size * 8) - 1;
75 for (auto field : provided_fields) {
76 if (previous_field) {
77 unsigned padding = previous_field->PaddingDistance(field);
78 if (padding) {
79 // -1 to end just before the previous field.
80 unsigned end = previous_field->GetStart() - 1;
81 // +1 because if you want to pad 1 bit you want to start and end
82 // on the same bit.
83 m_fields.push_back(Field("", field.GetEnd() + 1, end));
84 }
85 } else {
86 // This is the first field. Check that it starts at the register's MSB.
87 if (field.GetEnd() != register_msb)
88 m_fields.push_back(Field("", field.GetEnd() + 1, register_msb));
89 }
90 m_fields.push_back(field);
91 previous_field = field;
92 }
93
94 // The last field may not extend all the way to bit 0.
95 if (previous_field && previous_field->GetStart() != 0)
96 m_fields.push_back(Field("", 0, previous_field->GetStart() - 1));
97}
98
99RegisterFlags::RegisterFlags(std::string id, unsigned size,
100 const std::vector<Field> &fields)
101 : m_id(std::move(id)), m_size(size) {
102 SetFields(fields);
103}
104
105void RegisterFlags::log(Log *log) const {
106 LLDB_LOG(log, "ID: \"{0}\" Size: {1}", m_id.c_str(), m_size);
107 for (const Field &field : m_fields)
108 field.log(log);
109}
110
112 unsigned column_width) {
113 unsigned pad = column_width - content.GetString().size();
114 std::string pad_l;
115 std::string pad_r;
116 if (pad) {
117 pad_l = std::string(pad / 2, ' ');
118 pad_r = std::string((pad / 2) + (pad % 2), ' ');
119 }
120
121 StreamString aligned;
122 aligned.Printf("|%s%s%s", pad_l.c_str(), content.GetString().data(),
123 pad_r.c_str());
124 return aligned;
125}
126
127static void EmitTable(std::string &out, std::array<std::string, 3> &table) {
128 // Close the table.
129 for (std::string &line : table)
130 line += '|';
131
132 out += std::accumulate(table.begin() + 1, table.end(), table.front(),
133 [](std::string lhs, const auto &rhs) {
134 return std::move(lhs) + "\n" + rhs;
135 });
136}
137
138std::string RegisterFlags::AsTable(uint32_t max_width) const {
139 std::string table;
140 // position / gridline / name
141 std::array<std::string, 3> lines;
142 uint32_t current_width = 0;
143
144 for (const RegisterFlags::Field &field : m_fields) {
145 StreamString position;
146 if (field.GetEnd() == field.GetStart())
147 position.Printf(" %d ", field.GetEnd());
148 else
149 position.Printf(" %d-%d ", field.GetEnd(), field.GetStart());
150
151 StreamString name;
152 name.Printf(" %s ", field.GetName().c_str());
153
154 unsigned column_width = position.GetString().size();
155 unsigned name_width = name.GetString().size();
156 if (name_width > column_width)
157 column_width = name_width;
158
159 // If the next column would overflow and we have already formatted at least
160 // one column, put out what we have and move to a new table on the next line
161 // (+1 here because we need to cap the ends with '|'). If this is the first
162 // column, just let it overflow and we'll wrap next time around. There's not
163 // much we can do with a very small terminal.
164 if (current_width && ((current_width + column_width + 1) >= max_width)) {
165 EmitTable(table, lines);
166 // Blank line between each.
167 table += "\n\n";
168
169 for (std::string &line : lines)
170 line.clear();
171 current_width = 0;
172 }
173
174 StreamString aligned_position = FormatCell(position, column_width);
175 lines[0] += aligned_position.GetString();
176 StreamString grid;
177 grid << '|' << std::string(column_width, '-');
178 lines[1] += grid.GetString();
179 StreamString aligned_name = FormatCell(name, column_width);
180 lines[2] += aligned_name.GetString();
181
182 // +1 for the left side '|'.
183 current_width += column_width + 1;
184 }
185
186 // If we didn't overflow and still have table to print out.
187 if (lines[0].size())
188 EmitTable(table, lines);
189
190 return table;
191}
192
193void RegisterFlags::ToXML(Stream &strm) const {
194 // Example XML:
195 // <flags id="cpsr_flags" size="4">
196 // <field name="incorrect" start="0" end="0"/>
197 // </flags>
198 strm.Indent();
199 strm << "<flags id=\"" << GetID() << "\" ";
200 strm.Printf("size=\"%d\"", GetSize());
201 strm << ">";
202 for (const Field &field : m_fields) {
203 // Skip padding fields.
204 if (field.GetName().empty())
205 continue;
206
207 strm << "\n";
208 strm.IndentMore();
209 field.ToXML(strm);
210 strm.IndentLess();
211 }
212 strm.PutChar('\n');
213 strm.Indent("</flags>\n");
214}
215
217 // Example XML:
218 // <field name="correct" start="0" end="0"/>
219 strm.Indent();
220 strm << "<field name=\"";
221
222 std::string escaped_name;
223 llvm::raw_string_ostream escape_strm(escaped_name);
224 llvm::printHTMLEscaped(GetName(), escape_strm);
225 strm << escaped_name << "\" ";
226
227 strm.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd());
228 strm << "/>";
229}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:359
static StreamString FormatCell(const StreamString &content, unsigned column_width)
static void EmitTable(std::string &out, std::array< std::string, 3 > &table)
bool Overlaps(const Field &other) const
unsigned GetSizeInBits() const
Get size of the field in bits. Will always be at least 1.
Definition: RegisterFlags.h:34
unsigned PaddingDistance(const Field &other) const
Return the number of bits between this field and the other, that are not covered by either field.
Field(std::string name, unsigned start, unsigned end)
Where start is the least significant bit and end is the most significant bit.
const std::string & GetName() const
Definition: RegisterFlags.h:46
unsigned m_start
Start/end bit positions.
Definition: RegisterFlags.h:76
void ToXML(Stream &strm) const
Output XML that describes this field, to be inserted into a target XML file.
RegisterFlags(std::string id, unsigned size, const std::vector< Field > &fields)
This assumes that:
std::vector< Field > m_fields
void SetFields(const std::vector< Field > &fields)
Replace all the fields with the new set of fields.
void log(Log *log) const
const unsigned m_size
Size in bytes.
const std::string & GetID() const
void ToXML(Stream &strm) const
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.
Definition: Stream.h:28
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition: Stream.cpp:157
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
size_t PutChar(char ch)
Definition: Stream.cpp:131
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:198
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:195
A class that represents a running process on the host machine.