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