1dda28197Spatrick //===-- OptionGroupFormat.cpp ---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Interpreter/OptionGroupFormat.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Host/OptionParser.h"
12061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
13061da546Spatrick #include "lldb/Target/ExecutionContext.h"
14061da546Spatrick #include "lldb/Target/Target.h"
15061da546Spatrick
16061da546Spatrick using namespace lldb;
17061da546Spatrick using namespace lldb_private;
18061da546Spatrick
19*f6aab3d8Srobert static constexpr OptionDefinition g_default_option_definitions[] = {
20061da546Spatrick {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument,
21061da546Spatrick nullptr, {}, 0, eArgTypeFormat,
22061da546Spatrick "Specify a format to be used for display."},
23061da546Spatrick {LLDB_OPT_SET_2, false, "gdb-format", 'G', OptionParser::eRequiredArgument,
24061da546Spatrick nullptr, {}, 0, eArgTypeGDBFormat,
25061da546Spatrick "Specify a format using a GDB format specifier string."},
26061da546Spatrick {LLDB_OPT_SET_3, false, "size", 's', OptionParser::eRequiredArgument,
27061da546Spatrick nullptr, {}, 0, eArgTypeByteSize,
28061da546Spatrick "The size in bytes to use when displaying with the selected format."},
29061da546Spatrick {LLDB_OPT_SET_4, false, "count", 'c', OptionParser::eRequiredArgument,
30061da546Spatrick nullptr, {}, 0, eArgTypeCount,
31061da546Spatrick "The number of total items to display."},
32061da546Spatrick };
33061da546Spatrick
OptionGroupFormat(lldb::Format default_format,uint64_t default_byte_size,uint64_t default_count,OptionGroupFormatUsageTextVector usage_text_vector)34*f6aab3d8Srobert OptionGroupFormat::OptionGroupFormat(
35*f6aab3d8Srobert lldb::Format default_format, uint64_t default_byte_size,
36*f6aab3d8Srobert uint64_t default_count, OptionGroupFormatUsageTextVector usage_text_vector)
37*f6aab3d8Srobert : m_format(default_format, default_format),
38*f6aab3d8Srobert m_byte_size(default_byte_size, default_byte_size),
39*f6aab3d8Srobert m_count(default_count, default_count), m_prev_gdb_format('x'),
40*f6aab3d8Srobert m_prev_gdb_size('w'), m_has_gdb_format(false) {
41*f6aab3d8Srobert // Copy the default option definitions.
42*f6aab3d8Srobert std::copy(std::begin(g_default_option_definitions),
43*f6aab3d8Srobert std::end(g_default_option_definitions),
44*f6aab3d8Srobert std::begin(m_option_definitions));
45*f6aab3d8Srobert
46*f6aab3d8Srobert for (auto usage_text_tuple : usage_text_vector) {
47*f6aab3d8Srobert switch (std::get<0>(usage_text_tuple)) {
48*f6aab3d8Srobert case eArgTypeFormat:
49*f6aab3d8Srobert m_option_definitions[0].usage_text = std::get<1>(usage_text_tuple);
50*f6aab3d8Srobert break;
51*f6aab3d8Srobert case eArgTypeByteSize:
52*f6aab3d8Srobert m_option_definitions[2].usage_text = std::get<1>(usage_text_tuple);
53*f6aab3d8Srobert break;
54*f6aab3d8Srobert default:
55*f6aab3d8Srobert llvm_unreachable("Unimplemented option");
56*f6aab3d8Srobert }
57*f6aab3d8Srobert }
58*f6aab3d8Srobert }
59*f6aab3d8Srobert
GetDefinitions()60061da546Spatrick llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() {
61*f6aab3d8Srobert auto result = llvm::ArrayRef(m_option_definitions);
62061da546Spatrick if (m_byte_size.GetDefaultValue() < UINT64_MAX) {
63061da546Spatrick if (m_count.GetDefaultValue() < UINT64_MAX)
64061da546Spatrick return result;
65061da546Spatrick else
66061da546Spatrick return result.take_front(3);
67061da546Spatrick }
68061da546Spatrick return result.take_front(2);
69061da546Spatrick }
70061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)71061da546Spatrick Status OptionGroupFormat::SetOptionValue(uint32_t option_idx,
72061da546Spatrick llvm::StringRef option_arg,
73061da546Spatrick ExecutionContext *execution_context) {
74061da546Spatrick Status error;
75*f6aab3d8Srobert const int short_option = m_option_definitions[option_idx].short_option;
76061da546Spatrick
77061da546Spatrick switch (short_option) {
78061da546Spatrick case 'f':
79061da546Spatrick error = m_format.SetValueFromString(option_arg);
80061da546Spatrick break;
81061da546Spatrick
82061da546Spatrick case 'c':
83061da546Spatrick if (m_count.GetDefaultValue() == 0) {
84061da546Spatrick error.SetErrorString("--count option is disabled");
85061da546Spatrick } else {
86061da546Spatrick error = m_count.SetValueFromString(option_arg);
87061da546Spatrick if (m_count.GetCurrentValue() == 0)
88061da546Spatrick error.SetErrorStringWithFormat("invalid --count option value '%s'",
89061da546Spatrick option_arg.str().c_str());
90061da546Spatrick }
91061da546Spatrick break;
92061da546Spatrick
93061da546Spatrick case 's':
94061da546Spatrick if (m_byte_size.GetDefaultValue() == 0) {
95061da546Spatrick error.SetErrorString("--size option is disabled");
96061da546Spatrick } else {
97061da546Spatrick error = m_byte_size.SetValueFromString(option_arg);
98061da546Spatrick if (m_byte_size.GetCurrentValue() == 0)
99061da546Spatrick error.SetErrorStringWithFormat("invalid --size option value '%s'",
100061da546Spatrick option_arg.str().c_str());
101061da546Spatrick }
102061da546Spatrick break;
103061da546Spatrick
104061da546Spatrick case 'G': {
105061da546Spatrick uint64_t count = 0;
106061da546Spatrick llvm::StringRef gdb_format_str = option_arg;
107061da546Spatrick gdb_format_str.consumeInteger(0, count);
108061da546Spatrick
109061da546Spatrick Format format = eFormatDefault;
110061da546Spatrick uint32_t byte_size = 0;
111061da546Spatrick
112061da546Spatrick while (!gdb_format_str.empty() &&
113061da546Spatrick ParserGDBFormatLetter(execution_context, gdb_format_str[0], format,
114061da546Spatrick byte_size)) {
115061da546Spatrick gdb_format_str = gdb_format_str.drop_front();
116061da546Spatrick }
117061da546Spatrick
118061da546Spatrick // We the first character of the "gdb_format_str" is not the
119061da546Spatrick // NULL terminator, we didn't consume the entire string and
120061da546Spatrick // something is wrong. Also, if none of the format, size or count was
121061da546Spatrick // specified correctly, then abort.
122061da546Spatrick if (!gdb_format_str.empty() ||
123061da546Spatrick (format == eFormatInvalid && byte_size == 0 && count == 0)) {
124061da546Spatrick // Nothing got set correctly
125061da546Spatrick error.SetErrorStringWithFormat("invalid gdb format string '%s'",
126061da546Spatrick option_arg.str().c_str());
127061da546Spatrick return error;
128061da546Spatrick }
129061da546Spatrick
130061da546Spatrick // At least one of the format, size or count was set correctly. Anything
131061da546Spatrick // that wasn't set correctly should be set to the previous default
132061da546Spatrick if (format == eFormatInvalid)
133061da546Spatrick ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format,
134061da546Spatrick byte_size);
135061da546Spatrick
136061da546Spatrick const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
137061da546Spatrick const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
138061da546Spatrick if (byte_size_enabled) {
139061da546Spatrick // Byte size is enabled
140061da546Spatrick if (byte_size == 0)
141061da546Spatrick ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format,
142061da546Spatrick byte_size);
143061da546Spatrick } else {
144061da546Spatrick // Byte size is disabled, make sure it wasn't specified but if this is an
145061da546Spatrick // address, it's actually necessary to specify one so don't error out
146061da546Spatrick if (byte_size > 0 && format != lldb::eFormatAddressInfo) {
147061da546Spatrick error.SetErrorString(
148061da546Spatrick "this command doesn't support specifying a byte size");
149061da546Spatrick return error;
150061da546Spatrick }
151061da546Spatrick }
152061da546Spatrick
153061da546Spatrick if (count_enabled) {
154061da546Spatrick // Count is enabled and was not set, set it to the default for gdb format
155061da546Spatrick // statements (which is 1).
156061da546Spatrick if (count == 0)
157061da546Spatrick count = 1;
158061da546Spatrick } else {
159061da546Spatrick // Count is disabled, make sure it wasn't specified
160061da546Spatrick if (count > 0) {
161061da546Spatrick error.SetErrorString("this command doesn't support specifying a count");
162061da546Spatrick return error;
163061da546Spatrick }
164061da546Spatrick }
165061da546Spatrick
166061da546Spatrick m_format.SetCurrentValue(format);
167061da546Spatrick m_format.SetOptionWasSet();
168061da546Spatrick if (byte_size_enabled) {
169061da546Spatrick m_byte_size.SetCurrentValue(byte_size);
170061da546Spatrick m_byte_size.SetOptionWasSet();
171061da546Spatrick }
172061da546Spatrick if (count_enabled) {
173061da546Spatrick m_count.SetCurrentValue(count);
174061da546Spatrick m_count.SetOptionWasSet();
175061da546Spatrick }
176061da546Spatrick } break;
177061da546Spatrick
178061da546Spatrick default:
179061da546Spatrick llvm_unreachable("Unimplemented option");
180061da546Spatrick }
181061da546Spatrick
182061da546Spatrick return error;
183061da546Spatrick }
184061da546Spatrick
ParserGDBFormatLetter(ExecutionContext * execution_context,char format_letter,Format & format,uint32_t & byte_size)185061da546Spatrick bool OptionGroupFormat::ParserGDBFormatLetter(
186061da546Spatrick ExecutionContext *execution_context, char format_letter, Format &format,
187061da546Spatrick uint32_t &byte_size) {
188061da546Spatrick m_has_gdb_format = true;
189061da546Spatrick switch (format_letter) {
190061da546Spatrick case 'o':
191061da546Spatrick format = eFormatOctal;
192061da546Spatrick m_prev_gdb_format = format_letter;
193061da546Spatrick return true;
194061da546Spatrick case 'x':
195061da546Spatrick format = eFormatHex;
196061da546Spatrick m_prev_gdb_format = format_letter;
197061da546Spatrick return true;
198061da546Spatrick case 'd':
199061da546Spatrick format = eFormatDecimal;
200061da546Spatrick m_prev_gdb_format = format_letter;
201061da546Spatrick return true;
202061da546Spatrick case 'u':
203061da546Spatrick format = eFormatUnsigned;
204061da546Spatrick m_prev_gdb_format = format_letter;
205061da546Spatrick return true;
206061da546Spatrick case 't':
207061da546Spatrick format = eFormatBinary;
208061da546Spatrick m_prev_gdb_format = format_letter;
209061da546Spatrick return true;
210061da546Spatrick case 'f':
211061da546Spatrick format = eFormatFloat;
212061da546Spatrick m_prev_gdb_format = format_letter;
213061da546Spatrick return true;
214061da546Spatrick case 'a':
215061da546Spatrick format = eFormatAddressInfo;
216061da546Spatrick {
217061da546Spatrick TargetSP target_sp =
218061da546Spatrick execution_context ? execution_context->GetTargetSP() : TargetSP();
219061da546Spatrick if (target_sp)
220061da546Spatrick byte_size = target_sp->GetArchitecture().GetAddressByteSize();
221061da546Spatrick m_prev_gdb_format = format_letter;
222061da546Spatrick return true;
223061da546Spatrick }
224061da546Spatrick case 'i':
225061da546Spatrick format = eFormatInstruction;
226061da546Spatrick m_prev_gdb_format = format_letter;
227061da546Spatrick return true;
228061da546Spatrick case 'c':
229061da546Spatrick format = eFormatChar;
230061da546Spatrick m_prev_gdb_format = format_letter;
231061da546Spatrick return true;
232061da546Spatrick case 's':
233061da546Spatrick format = eFormatCString;
234061da546Spatrick m_prev_gdb_format = format_letter;
235061da546Spatrick return true;
236061da546Spatrick case 'T':
237061da546Spatrick format = eFormatOSType;
238061da546Spatrick m_prev_gdb_format = format_letter;
239061da546Spatrick return true;
240061da546Spatrick case 'A':
241061da546Spatrick format = eFormatHexFloat;
242061da546Spatrick m_prev_gdb_format = format_letter;
243061da546Spatrick return true;
244061da546Spatrick
245061da546Spatrick case 'b':
246061da546Spatrick case 'h':
247061da546Spatrick case 'w':
248061da546Spatrick case 'g':
249061da546Spatrick {
250061da546Spatrick // Size isn't used for printing instructions, so if a size is specified,
251061da546Spatrick // and the previous format was 'i', then we should reset it to the
252061da546Spatrick // default ('x'). Otherwise we'll continue to print as instructions,
253061da546Spatrick // which isn't expected.
254061da546Spatrick if (format_letter == 'b')
255061da546Spatrick byte_size = 1;
256061da546Spatrick else if (format_letter == 'h')
257061da546Spatrick byte_size = 2;
258061da546Spatrick else if (format_letter == 'w')
259061da546Spatrick byte_size = 4;
260061da546Spatrick else if (format_letter == 'g')
261061da546Spatrick byte_size = 8;
262061da546Spatrick
263061da546Spatrick m_prev_gdb_size = format_letter;
264061da546Spatrick if (m_prev_gdb_format == 'i')
265061da546Spatrick m_prev_gdb_format = 'x';
266061da546Spatrick return true;
267061da546Spatrick }
268061da546Spatrick break;
269061da546Spatrick default:
270061da546Spatrick break;
271061da546Spatrick }
272061da546Spatrick
273061da546Spatrick
274061da546Spatrick return false;
275061da546Spatrick }
276061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)277061da546Spatrick void OptionGroupFormat::OptionParsingStarting(
278061da546Spatrick ExecutionContext *execution_context) {
279061da546Spatrick m_format.Clear();
280061da546Spatrick m_byte_size.Clear();
281061da546Spatrick m_count.Clear();
282061da546Spatrick m_has_gdb_format = false;
283061da546Spatrick }
284