180814287SRaphael Isemann //===-- OptionGroupFormat.cpp ---------------------------------------------===//
284c39663SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
684c39663SGreg Clayton //
784c39663SGreg Clayton //===----------------------------------------------------------------------===//
884c39663SGreg Clayton 
94bee32e5SJohnny Chen #include "lldb/Interpreter/OptionGroupFormat.h"
1084c39663SGreg Clayton 
113eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
1281409635SGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h"
1381409635SGreg Clayton #include "lldb/Target/ExecutionContext.h"
1481409635SGreg Clayton #include "lldb/Target/Target.h"
1584c39663SGreg Clayton 
1684c39663SGreg Clayton using namespace lldb;
1784c39663SGreg Clayton using namespace lldb_private;
1884c39663SGreg Clayton 
19*7f05ff8bSVenkata Ramanaiah Nalamothu static constexpr OptionDefinition g_default_option_definitions[] = {
20b9c1b51eSKate Stone     {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument,
218fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeFormat,
22b9c1b51eSKate Stone      "Specify a format to be used for display."},
23b9c1b51eSKate Stone     {LLDB_OPT_SET_2, false, "gdb-format", 'G', OptionParser::eRequiredArgument,
248fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeGDBFormat,
25b9c1b51eSKate Stone      "Specify a format using a GDB format specifier string."},
26b9c1b51eSKate Stone     {LLDB_OPT_SET_3, false, "size", 's', OptionParser::eRequiredArgument,
278fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeByteSize,
28b9c1b51eSKate Stone      "The size in bytes to use when displaying with the selected format."},
29b9c1b51eSKate Stone     {LLDB_OPT_SET_4, false, "count", 'c', OptionParser::eRequiredArgument,
308fe53c49STatyana Krasnukha      nullptr, {}, 0, eArgTypeCount,
31b9c1b51eSKate Stone      "The number of total items to display."},
3284c39663SGreg Clayton };
3384c39663SGreg Clayton 
OptionGroupFormat(lldb::Format default_format,uint64_t default_byte_size,uint64_t default_count,OptionGroupFormatUsageTextVector usage_text_vector)34*7f05ff8bSVenkata Ramanaiah Nalamothu OptionGroupFormat::OptionGroupFormat(
35*7f05ff8bSVenkata Ramanaiah Nalamothu     lldb::Format default_format, uint64_t default_byte_size,
36*7f05ff8bSVenkata Ramanaiah Nalamothu     uint64_t default_count, OptionGroupFormatUsageTextVector usage_text_vector)
37*7f05ff8bSVenkata Ramanaiah Nalamothu     : m_format(default_format, default_format),
38*7f05ff8bSVenkata Ramanaiah Nalamothu       m_byte_size(default_byte_size, default_byte_size),
39*7f05ff8bSVenkata Ramanaiah Nalamothu       m_count(default_count, default_count), m_prev_gdb_format('x'),
40*7f05ff8bSVenkata Ramanaiah Nalamothu       m_prev_gdb_size('w') {
41*7f05ff8bSVenkata Ramanaiah Nalamothu   // Copy the default option definitions.
42*7f05ff8bSVenkata Ramanaiah Nalamothu   std::copy(std::begin(g_default_option_definitions),
43*7f05ff8bSVenkata Ramanaiah Nalamothu             std::end(g_default_option_definitions),
44*7f05ff8bSVenkata Ramanaiah Nalamothu             std::begin(m_option_definitions));
45*7f05ff8bSVenkata Ramanaiah Nalamothu 
46*7f05ff8bSVenkata Ramanaiah Nalamothu   for (auto usage_text_tuple : usage_text_vector) {
47*7f05ff8bSVenkata Ramanaiah Nalamothu     switch (std::get<0>(usage_text_tuple)) {
48*7f05ff8bSVenkata Ramanaiah Nalamothu     case eArgTypeFormat:
49*7f05ff8bSVenkata Ramanaiah Nalamothu       m_option_definitions[0].usage_text = std::get<1>(usage_text_tuple);
50*7f05ff8bSVenkata Ramanaiah Nalamothu       break;
51*7f05ff8bSVenkata Ramanaiah Nalamothu     case eArgTypeByteSize:
52*7f05ff8bSVenkata Ramanaiah Nalamothu       m_option_definitions[2].usage_text = std::get<1>(usage_text_tuple);
53*7f05ff8bSVenkata Ramanaiah Nalamothu       break;
54*7f05ff8bSVenkata Ramanaiah Nalamothu     default:
55*7f05ff8bSVenkata Ramanaiah Nalamothu       llvm_unreachable("Unimplemented option");
56*7f05ff8bSVenkata Ramanaiah Nalamothu     }
57*7f05ff8bSVenkata Ramanaiah Nalamothu   }
58*7f05ff8bSVenkata Ramanaiah Nalamothu }
59*7f05ff8bSVenkata Ramanaiah Nalamothu 
GetDefinitions()601f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() {
61*7f05ff8bSVenkata Ramanaiah Nalamothu   auto result = llvm::makeArrayRef(m_option_definitions);
62b9c1b51eSKate Stone   if (m_byte_size.GetDefaultValue() < UINT64_MAX) {
631deb7962SGreg Clayton     if (m_count.GetDefaultValue() < UINT64_MAX)
641f0f5b5bSZachary Turner       return result;
651deb7962SGreg Clayton     else
661f0f5b5bSZachary Turner       return result.take_front(3);
671deb7962SGreg Clayton   }
681f0f5b5bSZachary Turner   return result.take_front(2);
6984c39663SGreg Clayton }
7084c39663SGreg Clayton 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)7197206d57SZachary Turner Status OptionGroupFormat::SetOptionValue(uint32_t option_idx,
728cef4b0bSZachary Turner                                          llvm::StringRef option_arg,
73b9c1b51eSKate Stone                                          ExecutionContext *execution_context) {
7497206d57SZachary Turner   Status error;
75*7f05ff8bSVenkata Ramanaiah Nalamothu   const int short_option = m_option_definitions[option_idx].short_option;
7684c39663SGreg Clayton 
77b9c1b51eSKate Stone   switch (short_option) {
7884c39663SGreg Clayton   case 'f':
79c95f7e2aSPavel Labath     error = m_format.SetValueFromString(option_arg);
8084c39663SGreg Clayton     break;
8184c39663SGreg Clayton 
821deb7962SGreg Clayton   case 'c':
83b9c1b51eSKate Stone     if (m_count.GetDefaultValue() == 0) {
841deb7962SGreg Clayton       error.SetErrorString("--count option is disabled");
85b9c1b51eSKate Stone     } else {
86c95f7e2aSPavel Labath       error = m_count.SetValueFromString(option_arg);
871deb7962SGreg Clayton       if (m_count.GetCurrentValue() == 0)
88b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid --count option value '%s'",
898cef4b0bSZachary Turner                                        option_arg.str().c_str());
901deb7962SGreg Clayton     }
911deb7962SGreg Clayton     break;
921deb7962SGreg Clayton 
931deb7962SGreg Clayton   case 's':
94b9c1b51eSKate Stone     if (m_byte_size.GetDefaultValue() == 0) {
951deb7962SGreg Clayton       error.SetErrorString("--size option is disabled");
96b9c1b51eSKate Stone     } else {
97c95f7e2aSPavel Labath       error = m_byte_size.SetValueFromString(option_arg);
981deb7962SGreg Clayton       if (m_byte_size.GetCurrentValue() == 0)
99b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid --size option value '%s'",
1008cef4b0bSZachary Turner                                        option_arg.str().c_str());
1011deb7962SGreg Clayton     }
1021deb7962SGreg Clayton     break;
1031deb7962SGreg Clayton 
104b9c1b51eSKate Stone   case 'G': {
10586edbf41SGreg Clayton     uint64_t count = 0;
1068cef4b0bSZachary Turner     llvm::StringRef gdb_format_str = option_arg;
1078cef4b0bSZachary Turner     gdb_format_str.consumeInteger(0, count);
10886edbf41SGreg Clayton 
1097c533b24SGreg Clayton     Format format = eFormatDefault;
1107c533b24SGreg Clayton     uint32_t byte_size = 0;
11186edbf41SGreg Clayton 
1128cef4b0bSZachary Turner     while (!gdb_format_str.empty() &&
1138cef4b0bSZachary Turner            ParserGDBFormatLetter(execution_context, gdb_format_str[0], format,
114b9c1b51eSKate Stone                                  byte_size)) {
1158cef4b0bSZachary Turner       gdb_format_str = gdb_format_str.drop_front();
1167c533b24SGreg Clayton     }
11786edbf41SGreg Clayton 
1188cef4b0bSZachary Turner     // We the first character of the "gdb_format_str" is not the
11986edbf41SGreg Clayton     // NULL terminator, we didn't consume the entire string and
12005097246SAdrian Prantl     // something is wrong. Also, if none of the format, size or count was
12105097246SAdrian Prantl     // specified correctly, then abort.
1228cef4b0bSZachary Turner     if (!gdb_format_str.empty() ||
123b9c1b51eSKate Stone         (format == eFormatInvalid && byte_size == 0 && count == 0)) {
12486edbf41SGreg Clayton       // Nothing got set correctly
125b9c1b51eSKate Stone       error.SetErrorStringWithFormat("invalid gdb format string '%s'",
1268cef4b0bSZachary Turner                                      option_arg.str().c_str());
12786edbf41SGreg Clayton       return error;
12886edbf41SGreg Clayton     }
12986edbf41SGreg Clayton 
13005097246SAdrian Prantl     // At least one of the format, size or count was set correctly. Anything
13105097246SAdrian Prantl     // that wasn't set correctly should be set to the previous default
13286edbf41SGreg Clayton     if (format == eFormatInvalid)
133b9c1b51eSKate Stone       ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format,
134b9c1b51eSKate Stone                             byte_size);
13586edbf41SGreg Clayton 
13686edbf41SGreg Clayton     const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
13786edbf41SGreg Clayton     const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
138b9c1b51eSKate Stone     if (byte_size_enabled) {
13986edbf41SGreg Clayton       // Byte size is enabled
14086edbf41SGreg Clayton       if (byte_size == 0)
141b9c1b51eSKate Stone         ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format,
142b9c1b51eSKate Stone                               byte_size);
143b9c1b51eSKate Stone     } else {
14405097246SAdrian Prantl       // Byte size is disabled, make sure it wasn't specified but if this is an
14505097246SAdrian Prantl       // address, it's actually necessary to specify one so don't error out
146b9c1b51eSKate Stone       if (byte_size > 0 && format != lldb::eFormatAddressInfo) {
147b9c1b51eSKate Stone         error.SetErrorString(
148b9c1b51eSKate Stone             "this command doesn't support specifying a byte size");
14986edbf41SGreg Clayton         return error;
15086edbf41SGreg Clayton       }
15186edbf41SGreg Clayton     }
15286edbf41SGreg Clayton 
153b9c1b51eSKate Stone     if (count_enabled) {
154b9c1b51eSKate Stone       // Count is enabled and was not set, set it to the default for gdb format
155b9c1b51eSKate Stone       // statements (which is 1).
15686edbf41SGreg Clayton       if (count == 0)
157608036aeSJim Ingham         count = 1;
158b9c1b51eSKate Stone     } else {
15986edbf41SGreg Clayton       // Count is disabled, make sure it wasn't specified
160b9c1b51eSKate Stone       if (count > 0) {
16186edbf41SGreg Clayton         error.SetErrorString("this command doesn't support specifying a count");
16286edbf41SGreg Clayton         return error;
16386edbf41SGreg Clayton       }
16486edbf41SGreg Clayton     }
16586edbf41SGreg Clayton 
16686edbf41SGreg Clayton     m_format.SetCurrentValue(format);
16786edbf41SGreg Clayton     m_format.SetOptionWasSet();
168b9c1b51eSKate Stone     if (byte_size_enabled) {
16986edbf41SGreg Clayton       m_byte_size.SetCurrentValue(byte_size);
17086edbf41SGreg Clayton       m_byte_size.SetOptionWasSet();
17186edbf41SGreg Clayton     }
172b9c1b51eSKate Stone     if (count_enabled) {
17386edbf41SGreg Clayton       m_count.SetCurrentValue(count);
17486edbf41SGreg Clayton       m_count.SetOptionWasSet();
17586edbf41SGreg Clayton     }
176b9c1b51eSKate Stone   } break;
17786edbf41SGreg Clayton 
17884c39663SGreg Clayton   default:
17936162014SRaphael Isemann     llvm_unreachable("Unimplemented option");
18084c39663SGreg Clayton   }
18184c39663SGreg Clayton 
18284c39663SGreg Clayton   return error;
18384c39663SGreg Clayton }
18484c39663SGreg Clayton 
ParserGDBFormatLetter(ExecutionContext * execution_context,char format_letter,Format & format,uint32_t & byte_size)185b9c1b51eSKate Stone bool OptionGroupFormat::ParserGDBFormatLetter(
186b9c1b51eSKate Stone     ExecutionContext *execution_context, char format_letter, Format &format,
187b9c1b51eSKate Stone     uint32_t &byte_size) {
1886b4ddc65SEnrico Granata   m_has_gdb_format = true;
189b9c1b51eSKate Stone   switch (format_letter) {
190b9c1b51eSKate Stone   case 'o':
191b9c1b51eSKate Stone     format = eFormatOctal;
192b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
193b9c1b51eSKate Stone     return true;
194b9c1b51eSKate Stone   case 'x':
195b9c1b51eSKate Stone     format = eFormatHex;
196b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
197b9c1b51eSKate Stone     return true;
198b9c1b51eSKate Stone   case 'd':
199b9c1b51eSKate Stone     format = eFormatDecimal;
200b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
201b9c1b51eSKate Stone     return true;
202b9c1b51eSKate Stone   case 'u':
203b9c1b51eSKate Stone     format = eFormatUnsigned;
204b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
205b9c1b51eSKate Stone     return true;
206b9c1b51eSKate Stone   case 't':
207b9c1b51eSKate Stone     format = eFormatBinary;
208b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
209b9c1b51eSKate Stone     return true;
210b9c1b51eSKate Stone   case 'f':
211b9c1b51eSKate Stone     format = eFormatFloat;
212b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
213b9c1b51eSKate Stone     return true;
214b9c1b51eSKate Stone   case 'a':
215b9c1b51eSKate Stone     format = eFormatAddressInfo;
21686edbf41SGreg Clayton     {
217b9c1b51eSKate Stone       TargetSP target_sp =
218b9c1b51eSKate Stone           execution_context ? execution_context->GetTargetSP() : TargetSP();
219e1cfbc79STodd Fiala       if (target_sp)
220e1cfbc79STodd Fiala         byte_size = target_sp->GetArchitecture().GetAddressByteSize();
22181409635SGreg Clayton       m_prev_gdb_format = format_letter;
22281409635SGreg Clayton       return true;
22381409635SGreg Clayton     }
224b9c1b51eSKate Stone   case 'i':
225b9c1b51eSKate Stone     format = eFormatInstruction;
226b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
227b9c1b51eSKate Stone     return true;
228b9c1b51eSKate Stone   case 'c':
229b9c1b51eSKate Stone     format = eFormatChar;
230b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
231b9c1b51eSKate Stone     return true;
232b9c1b51eSKate Stone   case 's':
233b9c1b51eSKate Stone     format = eFormatCString;
234b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
235b9c1b51eSKate Stone     return true;
236b9c1b51eSKate Stone   case 'T':
237b9c1b51eSKate Stone     format = eFormatOSType;
238b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
239b9c1b51eSKate Stone     return true;
240b9c1b51eSKate Stone   case 'A':
241b9c1b51eSKate Stone     format = eFormatHexFloat;
242b9c1b51eSKate Stone     m_prev_gdb_format = format_letter;
243b9c1b51eSKate Stone     return true;
24422c9e7b2SJim Ingham 
245a1609ff6SJason Molenda   case 'b':
246a1609ff6SJason Molenda   case 'h':
247a1609ff6SJason Molenda   case 'w':
248a1609ff6SJason Molenda   case 'g':
249a1609ff6SJason Molenda     {
25005097246SAdrian Prantl       // Size isn't used for printing instructions, so if a size is specified,
25105097246SAdrian Prantl       // and the previous format was 'i', then we should reset it to the
25205097246SAdrian Prantl       // default ('x').  Otherwise we'll continue to print as instructions,
25322c9e7b2SJim Ingham       // which isn't expected.
254a1609ff6SJason Molenda       if (format_letter == 'b')
25522c9e7b2SJim Ingham           byte_size = 1;
256a1609ff6SJason Molenda       else if (format_letter == 'h')
25722c9e7b2SJim Ingham           byte_size = 2;
258a1609ff6SJason Molenda       else if (format_letter == 'w')
25922c9e7b2SJim Ingham           byte_size = 4;
260a1609ff6SJason Molenda       else if (format_letter == 'g')
26122c9e7b2SJim Ingham           byte_size = 8;
26222c9e7b2SJim Ingham 
26322c9e7b2SJim Ingham         m_prev_gdb_size = format_letter;
26422c9e7b2SJim Ingham         if (m_prev_gdb_format == 'i')
26522c9e7b2SJim Ingham           m_prev_gdb_format = 'x';
26622c9e7b2SJim Ingham         return true;
267a1609ff6SJason Molenda     }
26822c9e7b2SJim Ingham     break;
269b9c1b51eSKate Stone   default:
270b9c1b51eSKate Stone     break;
27186edbf41SGreg Clayton   }
272a1609ff6SJason Molenda 
273a1609ff6SJason Molenda 
2747c533b24SGreg Clayton   return false;
27586edbf41SGreg Clayton }
27686edbf41SGreg Clayton 
OptionParsingStarting(ExecutionContext * execution_context)277b9c1b51eSKate Stone void OptionGroupFormat::OptionParsingStarting(
278b9c1b51eSKate Stone     ExecutionContext *execution_context) {
27984c39663SGreg Clayton   m_format.Clear();
2801deb7962SGreg Clayton   m_byte_size.Clear();
2811deb7962SGreg Clayton   m_count.Clear();
2826b4ddc65SEnrico Granata   m_has_gdb_format = false;
28384c39663SGreg Clayton }
284