xref: /src/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- OptionArgParser.cpp -----------------------------------------------===//
2f73363f1SDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f73363f1SDimitry Andric //
7f73363f1SDimitry Andric //===----------------------------------------------------------------------===//
8f73363f1SDimitry Andric 
9f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
10f73363f1SDimitry Andric #include "lldb/DataFormatters/FormatManager.h"
11e3b55780SDimitry Andric #include "lldb/Target/ABI.h"
12ac9a064cSDimitry Andric #include "lldb/Target/RegisterContext.h"
13f73363f1SDimitry Andric #include "lldb/Target/Target.h"
14ac9a064cSDimitry Andric #include "lldb/Utility/RegisterValue.h"
15f73363f1SDimitry Andric #include "lldb/Utility/Status.h"
16f73363f1SDimitry Andric #include "lldb/Utility/StreamString.h"
17f73363f1SDimitry Andric 
18f73363f1SDimitry Andric using namespace lldb_private;
19f73363f1SDimitry Andric using namespace lldb;
20f73363f1SDimitry Andric 
ToBoolean(llvm::StringRef ref,bool fail_value,bool * success_ptr)21f73363f1SDimitry Andric bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value,
22f73363f1SDimitry Andric                                 bool *success_ptr) {
23f73363f1SDimitry Andric   if (success_ptr)
24f73363f1SDimitry Andric     *success_ptr = true;
25f73363f1SDimitry Andric   ref = ref.trim();
26344a3780SDimitry Andric   if (ref.equals_insensitive("false") || ref.equals_insensitive("off") ||
27344a3780SDimitry Andric       ref.equals_insensitive("no") || ref.equals_insensitive("0")) {
28f73363f1SDimitry Andric     return false;
29344a3780SDimitry Andric   } else if (ref.equals_insensitive("true") || ref.equals_insensitive("on") ||
30344a3780SDimitry Andric              ref.equals_insensitive("yes") || ref.equals_insensitive("1")) {
31f73363f1SDimitry Andric     return true;
32f73363f1SDimitry Andric   }
33f73363f1SDimitry Andric   if (success_ptr)
34f73363f1SDimitry Andric     *success_ptr = false;
35f73363f1SDimitry Andric   return fail_value;
36f73363f1SDimitry Andric }
37f73363f1SDimitry Andric 
ToBoolean(llvm::StringRef option_name,llvm::StringRef option_arg)38ac9a064cSDimitry Andric llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name,
39ac9a064cSDimitry Andric                                                 llvm::StringRef option_arg) {
40ac9a064cSDimitry Andric   bool parse_success;
41ac9a064cSDimitry Andric   const bool option_value =
42ac9a064cSDimitry Andric       ToBoolean(option_arg, false /* doesn't matter */, &parse_success);
43ac9a064cSDimitry Andric   if (parse_success)
44ac9a064cSDimitry Andric     return option_value;
45ac9a064cSDimitry Andric   else
46ac9a064cSDimitry Andric     return llvm::createStringError(
47ac9a064cSDimitry Andric         "Invalid boolean value for option '%s': '%s'",
48ac9a064cSDimitry Andric         option_name.str().c_str(),
49ac9a064cSDimitry Andric         option_arg.empty() ? "<null>" : option_arg.str().c_str());
50ac9a064cSDimitry Andric }
51ac9a064cSDimitry Andric 
ToChar(llvm::StringRef s,char fail_value,bool * success_ptr)52f73363f1SDimitry Andric char OptionArgParser::ToChar(llvm::StringRef s, char fail_value,
53f73363f1SDimitry Andric                              bool *success_ptr) {
54f73363f1SDimitry Andric   if (success_ptr)
55f73363f1SDimitry Andric     *success_ptr = false;
56f73363f1SDimitry Andric   if (s.size() != 1)
57f73363f1SDimitry Andric     return fail_value;
58f73363f1SDimitry Andric 
59f73363f1SDimitry Andric   if (success_ptr)
60f73363f1SDimitry Andric     *success_ptr = true;
61f73363f1SDimitry Andric   return s[0];
62f73363f1SDimitry Andric }
63f73363f1SDimitry Andric 
ToOptionEnum(llvm::StringRef s,const OptionEnumValues & enum_values,int32_t fail_value,Status & error)64f73363f1SDimitry Andric int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s,
6594994d37SDimitry Andric                                       const OptionEnumValues &enum_values,
66f73363f1SDimitry Andric                                       int32_t fail_value, Status &error) {
67f73363f1SDimitry Andric   error.Clear();
6894994d37SDimitry Andric   if (enum_values.empty()) {
69f73363f1SDimitry Andric     error.SetErrorString("invalid enumeration argument");
70f73363f1SDimitry Andric     return fail_value;
71f73363f1SDimitry Andric   }
72f73363f1SDimitry Andric 
73f73363f1SDimitry Andric   if (s.empty()) {
74f73363f1SDimitry Andric     error.SetErrorString("empty enumeration string");
75f73363f1SDimitry Andric     return fail_value;
76f73363f1SDimitry Andric   }
77f73363f1SDimitry Andric 
7894994d37SDimitry Andric   for (const auto &enum_value : enum_values) {
7994994d37SDimitry Andric     llvm::StringRef this_enum(enum_value.string_value);
80312c0ed1SDimitry Andric     if (this_enum.starts_with(s))
8194994d37SDimitry Andric       return enum_value.value;
82f73363f1SDimitry Andric   }
83f73363f1SDimitry Andric 
84f73363f1SDimitry Andric   StreamString strm;
85f73363f1SDimitry Andric   strm.PutCString("invalid enumeration value, valid values are: ");
8694994d37SDimitry Andric   bool is_first = true;
8794994d37SDimitry Andric   for (const auto &enum_value : enum_values) {
8894994d37SDimitry Andric     strm.Printf("%s\"%s\"",
8994994d37SDimitry Andric         is_first ? is_first = false,"" : ", ", enum_value.string_value);
90f73363f1SDimitry Andric   }
91f73363f1SDimitry Andric   error.SetErrorString(strm.GetString());
92f73363f1SDimitry Andric   return fail_value;
93f73363f1SDimitry Andric }
94f73363f1SDimitry Andric 
ToFormat(const char * s,lldb::Format & format,size_t * byte_size_ptr)95f73363f1SDimitry Andric Status OptionArgParser::ToFormat(const char *s, lldb::Format &format,
96f73363f1SDimitry Andric                                  size_t *byte_size_ptr) {
97f73363f1SDimitry Andric   format = eFormatInvalid;
98f73363f1SDimitry Andric   Status error;
99f73363f1SDimitry Andric 
100f73363f1SDimitry Andric   if (s && s[0]) {
101f73363f1SDimitry Andric     if (byte_size_ptr) {
102f73363f1SDimitry Andric       if (isdigit(s[0])) {
103f73363f1SDimitry Andric         char *format_char = nullptr;
104f73363f1SDimitry Andric         unsigned long byte_size = ::strtoul(s, &format_char, 0);
105f73363f1SDimitry Andric         if (byte_size != ULONG_MAX)
106f73363f1SDimitry Andric           *byte_size_ptr = byte_size;
107f73363f1SDimitry Andric         s = format_char;
108f73363f1SDimitry Andric       } else
109f73363f1SDimitry Andric         *byte_size_ptr = 0;
110f73363f1SDimitry Andric     }
111f73363f1SDimitry Andric 
112ac9a064cSDimitry Andric     if (!FormatManager::GetFormatFromCString(s, format)) {
113f73363f1SDimitry Andric       StreamString error_strm;
114f73363f1SDimitry Andric       error_strm.Printf(
115f73363f1SDimitry Andric           "Invalid format character or name '%s'. Valid values are:\n", s);
116f73363f1SDimitry Andric       for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) {
117f73363f1SDimitry Andric         char format_char = FormatManager::GetFormatAsFormatChar(f);
118f73363f1SDimitry Andric         if (format_char)
119f73363f1SDimitry Andric           error_strm.Printf("'%c' or ", format_char);
120f73363f1SDimitry Andric 
121f73363f1SDimitry Andric         error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f));
122f73363f1SDimitry Andric         error_strm.EOL();
123f73363f1SDimitry Andric       }
124f73363f1SDimitry Andric 
125f73363f1SDimitry Andric       if (byte_size_ptr)
126f73363f1SDimitry Andric         error_strm.PutCString(
127f73363f1SDimitry Andric             "An optional byte size can precede the format character.\n");
128f73363f1SDimitry Andric       error.SetErrorString(error_strm.GetString());
129f73363f1SDimitry Andric     }
130f73363f1SDimitry Andric 
131f73363f1SDimitry Andric     if (error.Fail())
132f73363f1SDimitry Andric       return error;
133f73363f1SDimitry Andric   } else {
134f73363f1SDimitry Andric     error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid");
135f73363f1SDimitry Andric   }
136f73363f1SDimitry Andric   return error;
137f73363f1SDimitry Andric }
138f73363f1SDimitry Andric 
ToScriptLanguage(llvm::StringRef s,lldb::ScriptLanguage fail_value,bool * success_ptr)139f73363f1SDimitry Andric lldb::ScriptLanguage OptionArgParser::ToScriptLanguage(
140f73363f1SDimitry Andric     llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr) {
141f73363f1SDimitry Andric   if (success_ptr)
142f73363f1SDimitry Andric     *success_ptr = true;
143f73363f1SDimitry Andric 
144344a3780SDimitry Andric   if (s.equals_insensitive("python"))
145f73363f1SDimitry Andric     return eScriptLanguagePython;
146344a3780SDimitry Andric   if (s.equals_insensitive("lua"))
147706b4fc4SDimitry Andric     return eScriptLanguageLua;
148344a3780SDimitry Andric   if (s.equals_insensitive("default"))
149f73363f1SDimitry Andric     return eScriptLanguageDefault;
150344a3780SDimitry Andric   if (s.equals_insensitive("none"))
151f73363f1SDimitry Andric     return eScriptLanguageNone;
152f73363f1SDimitry Andric 
153f73363f1SDimitry Andric   if (success_ptr)
154f73363f1SDimitry Andric     *success_ptr = false;
155f73363f1SDimitry Andric   return fail_value;
156f73363f1SDimitry Andric }
157f73363f1SDimitry Andric 
ToRawAddress(const ExecutionContext * exe_ctx,llvm::StringRef s,lldb::addr_t fail_value,Status * error_ptr)1587fa27ce4SDimitry Andric lldb::addr_t OptionArgParser::ToRawAddress(const ExecutionContext *exe_ctx,
1597fa27ce4SDimitry Andric                                            llvm::StringRef s,
1607fa27ce4SDimitry Andric                                            lldb::addr_t fail_value,
1617fa27ce4SDimitry Andric                                            Status *error_ptr) {
1627fa27ce4SDimitry Andric   std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr);
1637fa27ce4SDimitry Andric   return maybe_addr ? *maybe_addr : fail_value;
1647fa27ce4SDimitry Andric }
1657fa27ce4SDimitry Andric 
ToAddress(const ExecutionContext * exe_ctx,llvm::StringRef s,lldb::addr_t fail_value,Status * error_ptr)166f73363f1SDimitry Andric lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx,
167f73363f1SDimitry Andric                                         llvm::StringRef s,
168f73363f1SDimitry Andric                                         lldb::addr_t fail_value,
169f73363f1SDimitry Andric                                         Status *error_ptr) {
1707fa27ce4SDimitry Andric   std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr);
1717fa27ce4SDimitry Andric   if (!maybe_addr)
1727fa27ce4SDimitry Andric     return fail_value;
1737fa27ce4SDimitry Andric 
1747fa27ce4SDimitry Andric   lldb::addr_t addr = *maybe_addr;
1757fa27ce4SDimitry Andric 
1767fa27ce4SDimitry Andric   if (Process *process = exe_ctx->GetProcessPtr())
1777fa27ce4SDimitry Andric     if (ABISP abi_sp = process->GetABI())
1787fa27ce4SDimitry Andric       addr = abi_sp->FixCodeAddress(addr);
1797fa27ce4SDimitry Andric 
1807fa27ce4SDimitry Andric   return addr;
1817fa27ce4SDimitry Andric }
1827fa27ce4SDimitry Andric 
1837fa27ce4SDimitry Andric std::optional<lldb::addr_t>
DoToAddress(const ExecutionContext * exe_ctx,llvm::StringRef s,Status * error_ptr)1847fa27ce4SDimitry Andric OptionArgParser::DoToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s,
1857fa27ce4SDimitry Andric                              Status *error_ptr) {
186f73363f1SDimitry Andric   if (s.empty()) {
187f73363f1SDimitry Andric     if (error_ptr)
188f73363f1SDimitry Andric       error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"",
189f73363f1SDimitry Andric                                           s.str().c_str());
1907fa27ce4SDimitry Andric     return {};
191f73363f1SDimitry Andric   }
192f73363f1SDimitry Andric 
193f73363f1SDimitry Andric   llvm::StringRef sref = s;
194f73363f1SDimitry Andric 
195f73363f1SDimitry Andric   lldb::addr_t addr = LLDB_INVALID_ADDRESS;
196f73363f1SDimitry Andric   if (!s.getAsInteger(0, addr)) {
197f73363f1SDimitry Andric     if (error_ptr)
198f73363f1SDimitry Andric       error_ptr->Clear();
1997fa27ce4SDimitry Andric 
200f73363f1SDimitry Andric     return addr;
201f73363f1SDimitry Andric   }
202f73363f1SDimitry Andric 
203f73363f1SDimitry Andric   // Try base 16 with no prefix...
204f73363f1SDimitry Andric   if (!s.getAsInteger(16, addr)) {
205f73363f1SDimitry Andric     if (error_ptr)
206f73363f1SDimitry Andric       error_ptr->Clear();
207f73363f1SDimitry Andric     return addr;
208f73363f1SDimitry Andric   }
209f73363f1SDimitry Andric 
210f73363f1SDimitry Andric   Target *target = nullptr;
211f73363f1SDimitry Andric   if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) {
212f73363f1SDimitry Andric     if (error_ptr)
213f73363f1SDimitry Andric       error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"",
214f73363f1SDimitry Andric                                           s.str().c_str());
2157fa27ce4SDimitry Andric     return {};
216f73363f1SDimitry Andric   }
217f73363f1SDimitry Andric 
218f73363f1SDimitry Andric   lldb::ValueObjectSP valobj_sp;
219f73363f1SDimitry Andric   EvaluateExpressionOptions options;
220f73363f1SDimitry Andric   options.SetCoerceToId(false);
221f73363f1SDimitry Andric   options.SetUnwindOnError(true);
222f73363f1SDimitry Andric   options.SetKeepInMemory(false);
223f73363f1SDimitry Andric   options.SetTryAllThreads(true);
224f73363f1SDimitry Andric 
225f73363f1SDimitry Andric   ExpressionResults expr_result =
226f73363f1SDimitry Andric       target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options);
227f73363f1SDimitry Andric 
228f73363f1SDimitry Andric   bool success = false;
229f73363f1SDimitry Andric   if (expr_result == eExpressionCompleted) {
230f73363f1SDimitry Andric     if (valobj_sp)
231f73363f1SDimitry Andric       valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable(
232f73363f1SDimitry Andric           valobj_sp->GetDynamicValueType(), true);
233f73363f1SDimitry Andric     // Get the address to watch.
234f73363f1SDimitry Andric     if (valobj_sp)
2357fa27ce4SDimitry Andric       addr = valobj_sp->GetValueAsUnsigned(0, &success);
236f73363f1SDimitry Andric     if (success) {
237f73363f1SDimitry Andric       if (error_ptr)
238f73363f1SDimitry Andric         error_ptr->Clear();
239f73363f1SDimitry Andric       return addr;
240b1c73532SDimitry Andric     }
241b1c73532SDimitry Andric     if (error_ptr)
242f73363f1SDimitry Andric       error_ptr->SetErrorStringWithFormat(
243f73363f1SDimitry Andric           "address expression \"%s\" resulted in a value whose type "
244f73363f1SDimitry Andric           "can't be converted to an address: %s",
245f73363f1SDimitry Andric           s.str().c_str(), valobj_sp->GetTypeName().GetCString());
246b1c73532SDimitry Andric     return {};
247f73363f1SDimitry Andric   }
248f73363f1SDimitry Andric 
249f73363f1SDimitry Andric   // Since the compiler can't handle things like "main + 12" we should try to
250f73363f1SDimitry Andric   // do this for now. The compiler doesn't like adding offsets to function
251f73363f1SDimitry Andric   // pointer types.
252ac9a064cSDimitry Andric   // Some languages also don't have a natural representation for register
253ac9a064cSDimitry Andric   // values (e.g. swift) so handle simple uses of them here as well.
254ac9a064cSDimitry Andric   // We use a regex to parse these forms, the regex handles:
255ac9a064cSDimitry Andric   // $reg_name
256ac9a064cSDimitry Andric   // $reg_name+offset
257ac9a064cSDimitry Andric   // symbol_name+offset
258ac9a064cSDimitry Andric   //
259ac9a064cSDimitry Andric   // The important matching elements in the regex below are:
260ac9a064cSDimitry Andric   // 1: The reg name if there's no +offset
261ac9a064cSDimitry Andric   // 3: The symbol/reg name if there is an offset
262ac9a064cSDimitry Andric   // 4: +/-
263ac9a064cSDimitry Andric   // 5: The offset value.
264f73363f1SDimitry Andric   static RegularExpression g_symbol_plus_offset_regex(
265ac9a064cSDimitry Andric       "^(\\$[^ +-]+)|(([^ +-]+)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*)$");
266f73363f1SDimitry Andric 
267ead24645SDimitry Andric   llvm::SmallVector<llvm::StringRef, 4> matches;
268ead24645SDimitry Andric   if (g_symbol_plus_offset_regex.Execute(sref, &matches)) {
269ead24645SDimitry Andric     uint64_t offset = 0;
270ac9a064cSDimitry Andric     llvm::StringRef name;
271ac9a064cSDimitry Andric     if (!matches[1].empty())
272ac9a064cSDimitry Andric       name = matches[1];
273ac9a064cSDimitry Andric     else
274ac9a064cSDimitry Andric       name = matches[3];
275ac9a064cSDimitry Andric 
276ac9a064cSDimitry Andric     llvm::StringRef sign = matches[4];
277ac9a064cSDimitry Andric     llvm::StringRef str_offset = matches[5];
278ac9a064cSDimitry Andric 
279ac9a064cSDimitry Andric     // Some languages don't have a natural type for register values, but it
280ac9a064cSDimitry Andric     // is still useful to look them up here:
281ac9a064cSDimitry Andric     std::optional<lldb::addr_t> register_value;
282ac9a064cSDimitry Andric     StackFrame *frame = exe_ctx->GetFramePtr();
283ac9a064cSDimitry Andric     llvm::StringRef reg_name = name;
284ac9a064cSDimitry Andric     if (frame && reg_name.consume_front("$")) {
285ac9a064cSDimitry Andric       RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
286ac9a064cSDimitry Andric       if (reg_ctx_sp) {
287ac9a064cSDimitry Andric         const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfoByName(reg_name);
288ac9a064cSDimitry Andric         if (reg_info) {
289ac9a064cSDimitry Andric           RegisterValue reg_val;
290ac9a064cSDimitry Andric           bool success = reg_ctx_sp->ReadRegister(reg_info, reg_val);
291ac9a064cSDimitry Andric           if (success && reg_val.GetType() != RegisterValue::eTypeInvalid) {
292ac9a064cSDimitry Andric             register_value = reg_val.GetAsUInt64(0, &success);
293ac9a064cSDimitry Andric             if (!success)
294ac9a064cSDimitry Andric               register_value.reset();
295ac9a064cSDimitry Andric           }
296ac9a064cSDimitry Andric         }
297ac9a064cSDimitry Andric       }
298ac9a064cSDimitry Andric     }
299ac9a064cSDimitry Andric     if (!str_offset.empty() && !str_offset.getAsInteger(0, offset)) {
300f73363f1SDimitry Andric       Status error;
301ac9a064cSDimitry Andric       if (register_value)
302ac9a064cSDimitry Andric         addr = register_value.value();
303ac9a064cSDimitry Andric       else
304b1c73532SDimitry Andric         addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error);
305f73363f1SDimitry Andric       if (addr != LLDB_INVALID_ADDRESS) {
306ead24645SDimitry Andric         if (sign[0] == '+')
307f73363f1SDimitry Andric           return addr + offset;
308f73363f1SDimitry Andric         return addr - offset;
309f73363f1SDimitry Andric       }
310ac9a064cSDimitry Andric     } else if (register_value)
311ac9a064cSDimitry Andric       // In the case of register values, someone might just want to get the
312ac9a064cSDimitry Andric       // value in a language whose expression parser doesn't support registers.
313ac9a064cSDimitry Andric       return register_value.value();
314f73363f1SDimitry Andric   }
315f73363f1SDimitry Andric 
316b1c73532SDimitry Andric   if (error_ptr)
317f73363f1SDimitry Andric     error_ptr->SetErrorStringWithFormat(
318f73363f1SDimitry Andric         "address expression \"%s\" evaluation failed", s.str().c_str());
3197fa27ce4SDimitry Andric   return {};
320f73363f1SDimitry Andric }
321