1 //===-- RegisterFlags.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Target/RegisterFlags.h"
10 #include "lldb/Utility/Log.h"
11 #include "lldb/Utility/StreamString.h"
13 #include "llvm/ADT/StringExtras.h"
18 using namespace lldb_private
;
20 RegisterFlags::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.");
25 void RegisterFlags::Field::log(Log
*log
) const {
26 LLDB_LOG(log
, " Name: \"{0}\" Start: {1} End: {2}", m_name
.c_str(), m_start
,
30 bool 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
;
36 unsigned 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.");
41 // If they don't overlap they are either next to each other or separated
42 // by some number of bits.
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;
49 lhs_start
= other
.GetStart();
50 rhs_end
= GetStart() + GetSizeInBits() - 1;
53 return lhs_start
- rhs_end
- 1;
56 RegisterFlags::RegisterFlags(std::string id
, unsigned size
,
57 const std::vector
<Field
> &fields
)
58 : m_id(std::move(id
)), m_size(size
) {
59 // We expect that the XML processor will discard anything describing flags but
61 assert(fields
.size() && "Some fields must be provided.");
63 // We expect that these are unsorted but do not overlap.
64 // They could fill the register but may have gaps.
65 std::vector
<Field
> provided_fields
= fields
;
66 m_fields
.reserve(provided_fields
.size());
68 // ProcessGDBRemote should have sorted these in descending order already.
69 assert(std::is_sorted(provided_fields
.rbegin(), provided_fields
.rend()));
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
= (size
* 8) - 1;
75 for (auto field
: provided_fields
) {
77 unsigned padding
= previous_field
->PaddingDistance(field
);
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
83 m_fields
.push_back(Field("", field
.GetEnd() + 1, end
));
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
));
90 m_fields
.push_back(field
);
91 previous_field
= field
;
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));
99 void RegisterFlags::log(Log
*log
) const {
100 LLDB_LOG(log
, "ID: \"{0}\" Size: {1}", m_id
.c_str(), m_size
);
101 for (const Field
&field
: m_fields
)
105 static StreamString
FormatCell(const StreamString
&content
,
106 unsigned column_width
) {
107 unsigned pad
= column_width
- content
.GetString().size();
111 pad_l
= std::string(pad
/ 2, ' ');
112 pad_r
= std::string((pad
/ 2) + (pad
% 2), ' ');
115 StreamString aligned
;
116 aligned
.Printf("|%s%s%s", pad_l
.c_str(), content
.GetString().data(),
121 static void EmitTable(std::string
&out
, std::array
<std::string
, 3> &table
) {
123 for (std::string
&line
: table
)
126 out
+= std::accumulate(table
.begin() + 1, table
.end(), table
.front(),
127 [](std::string lhs
, const auto &rhs
) {
128 return std::move(lhs
) + "\n" + rhs
;
132 std::string
RegisterFlags::AsTable(uint32_t max_width
) const {
134 // position / gridline / name
135 std::array
<std::string
, 3> lines
;
136 uint32_t current_width
= 0;
138 for (const RegisterFlags::Field
&field
: m_fields
) {
139 StreamString position
;
140 if (field
.GetEnd() == field
.GetStart())
141 position
.Printf(" %d ", field
.GetEnd());
143 position
.Printf(" %d-%d ", field
.GetEnd(), field
.GetStart());
146 name
.Printf(" %s ", field
.GetName().c_str());
148 unsigned column_width
= position
.GetString().size();
149 unsigned name_width
= name
.GetString().size();
150 if (name_width
> column_width
)
151 column_width
= name_width
;
153 // If the next column would overflow and we have already formatted at least
154 // one column, put out what we have and move to a new table on the next line
155 // (+1 here because we need to cap the ends with '|'). If this is the first
156 // column, just let it overflow and we'll wrap next time around. There's not
157 // much we can do with a very small terminal.
158 if (current_width
&& ((current_width
+ column_width
+ 1) >= max_width
)) {
159 EmitTable(table
, lines
);
160 // Blank line between each.
163 for (std::string
&line
: lines
)
168 StreamString aligned_position
= FormatCell(position
, column_width
);
169 lines
[0] += aligned_position
.GetString();
171 grid
<< '|' << std::string(column_width
, '-');
172 lines
[1] += grid
.GetString();
173 StreamString aligned_name
= FormatCell(name
, column_width
);
174 lines
[2] += aligned_name
.GetString();
176 // +1 for the left side '|'.
177 current_width
+= column_width
+ 1;
180 // If we didn't overflow and still have table to print out.
182 EmitTable(table
, lines
);
187 void RegisterFlags::ToXML(StreamString
&strm
) const {
189 // <flags id="cpsr_flags" size="4">
190 // <field name="incorrect" start="0" end="0"/>
193 strm
<< "<flags id=\"" << GetID() << "\" ";
194 strm
.Printf("size=\"%d\"", GetSize());
196 for (const Field
&field
: m_fields
) {
197 // Skip padding fields.
198 if (field
.GetName().empty())
207 strm
.Indent("</flags>\n");
210 void RegisterFlags::Field::ToXML(StreamString
&strm
) const {
212 // <field name="correct" start="0" end="0"/>
214 strm
<< "<field name=\"";
216 std::string escaped_name
;
217 llvm::raw_string_ostream
escape_strm(escaped_name
);
218 llvm::printHTMLEscaped(GetName(), escape_strm
);
219 strm
<< escaped_name
<< "\" ";
221 strm
.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd());