| //===-- OptionArgParser.cpp -----------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lldb/Interpreter/OptionArgParser.h" |
| #include "lldb/DataFormatters/FormatManager.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Utility/Status.h" |
| #include "lldb/Utility/StreamString.h" |
| |
| using namespace lldb_private; |
| using namespace lldb; |
| |
| bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value, |
| bool *success_ptr) { |
| if (success_ptr) |
| *success_ptr = true; |
| ref = ref.trim(); |
| if (ref.equals_insensitive("false") || ref.equals_insensitive("off") || |
| ref.equals_insensitive("no") || ref.equals_insensitive("0")) { |
| return false; |
| } else if (ref.equals_insensitive("true") || ref.equals_insensitive("on") || |
| ref.equals_insensitive("yes") || ref.equals_insensitive("1")) { |
| return true; |
| } |
| if (success_ptr) |
| *success_ptr = false; |
| return fail_value; |
| } |
| |
| char OptionArgParser::ToChar(llvm::StringRef s, char fail_value, |
| bool *success_ptr) { |
| if (success_ptr) |
| *success_ptr = false; |
| if (s.size() != 1) |
| return fail_value; |
| |
| if (success_ptr) |
| *success_ptr = true; |
| return s[0]; |
| } |
| |
| int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s, |
| const OptionEnumValues &enum_values, |
| int32_t fail_value, Status &error) { |
| error.Clear(); |
| if (enum_values.empty()) { |
| error.SetErrorString("invalid enumeration argument"); |
| return fail_value; |
| } |
| |
| if (s.empty()) { |
| error.SetErrorString("empty enumeration string"); |
| return fail_value; |
| } |
| |
| for (const auto &enum_value : enum_values) { |
| llvm::StringRef this_enum(enum_value.string_value); |
| if (this_enum.startswith(s)) |
| return enum_value.value; |
| } |
| |
| StreamString strm; |
| strm.PutCString("invalid enumeration value, valid values are: "); |
| bool is_first = true; |
| for (const auto &enum_value : enum_values) { |
| strm.Printf("%s\"%s\"", |
| is_first ? is_first = false,"" : ", ", enum_value.string_value); |
| } |
| error.SetErrorString(strm.GetString()); |
| return fail_value; |
| } |
| |
| Status OptionArgParser::ToFormat(const char *s, lldb::Format &format, |
| size_t *byte_size_ptr) { |
| format = eFormatInvalid; |
| Status error; |
| |
| if (s && s[0]) { |
| if (byte_size_ptr) { |
| if (isdigit(s[0])) { |
| char *format_char = nullptr; |
| unsigned long byte_size = ::strtoul(s, &format_char, 0); |
| if (byte_size != ULONG_MAX) |
| *byte_size_ptr = byte_size; |
| s = format_char; |
| } else |
| *byte_size_ptr = 0; |
| } |
| |
| const bool partial_match_ok = true; |
| if (!FormatManager::GetFormatFromCString(s, partial_match_ok, format)) { |
| StreamString error_strm; |
| error_strm.Printf( |
| "Invalid format character or name '%s'. Valid values are:\n", s); |
| for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) { |
| char format_char = FormatManager::GetFormatAsFormatChar(f); |
| if (format_char) |
| error_strm.Printf("'%c' or ", format_char); |
| |
| error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f)); |
| error_strm.EOL(); |
| } |
| |
| if (byte_size_ptr) |
| error_strm.PutCString( |
| "An optional byte size can precede the format character.\n"); |
| error.SetErrorString(error_strm.GetString()); |
| } |
| |
| if (error.Fail()) |
| return error; |
| } else { |
| error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); |
| } |
| return error; |
| } |
| |
| lldb::ScriptLanguage OptionArgParser::ToScriptLanguage( |
| llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr) { |
| if (success_ptr) |
| *success_ptr = true; |
| |
| if (s.equals_insensitive("python")) |
| return eScriptLanguagePython; |
| if (s.equals_insensitive("lua")) |
| return eScriptLanguageLua; |
| if (s.equals_insensitive("default")) |
| return eScriptLanguageDefault; |
| if (s.equals_insensitive("none")) |
| return eScriptLanguageNone; |
| |
| if (success_ptr) |
| *success_ptr = false; |
| return fail_value; |
| } |
| |
| lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx, |
| llvm::StringRef s, |
| lldb::addr_t fail_value, |
| Status *error_ptr) { |
| bool error_set = false; |
| if (s.empty()) { |
| if (error_ptr) |
| error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", |
| s.str().c_str()); |
| return fail_value; |
| } |
| |
| llvm::StringRef sref = s; |
| |
| lldb::addr_t addr = LLDB_INVALID_ADDRESS; |
| if (!s.getAsInteger(0, addr)) { |
| if (error_ptr) |
| error_ptr->Clear(); |
| return addr; |
| } |
| |
| // Try base 16 with no prefix... |
| if (!s.getAsInteger(16, addr)) { |
| if (error_ptr) |
| error_ptr->Clear(); |
| return addr; |
| } |
| |
| Target *target = nullptr; |
| if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) { |
| if (error_ptr) |
| error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", |
| s.str().c_str()); |
| return fail_value; |
| } |
| |
| lldb::ValueObjectSP valobj_sp; |
| EvaluateExpressionOptions options; |
| options.SetCoerceToId(false); |
| options.SetUnwindOnError(true); |
| options.SetKeepInMemory(false); |
| options.SetTryAllThreads(true); |
| |
| ExpressionResults expr_result = |
| target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options); |
| |
| bool success = false; |
| if (expr_result == eExpressionCompleted) { |
| if (valobj_sp) |
| valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable( |
| valobj_sp->GetDynamicValueType(), true); |
| // Get the address to watch. |
| if (valobj_sp) |
| addr = valobj_sp->GetValueAsUnsigned(fail_value, &success); |
| if (success) { |
| if (error_ptr) |
| error_ptr->Clear(); |
| return addr; |
| } else { |
| if (error_ptr) { |
| error_set = true; |
| error_ptr->SetErrorStringWithFormat( |
| "address expression \"%s\" resulted in a value whose type " |
| "can't be converted to an address: %s", |
| s.str().c_str(), valobj_sp->GetTypeName().GetCString()); |
| } |
| } |
| |
| } else { |
| // Since the compiler can't handle things like "main + 12" we should try to |
| // do this for now. The compiler doesn't like adding offsets to function |
| // pointer types. |
| static RegularExpression g_symbol_plus_offset_regex( |
| "^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); |
| |
| llvm::SmallVector<llvm::StringRef, 4> matches; |
| if (g_symbol_plus_offset_regex.Execute(sref, &matches)) { |
| uint64_t offset = 0; |
| std::string name = matches[1].str(); |
| std::string sign = matches[2].str(); |
| std::string str_offset = matches[3].str(); |
| if (!llvm::StringRef(str_offset).getAsInteger(0, offset)) { |
| Status error; |
| addr = ToAddress(exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error); |
| if (addr != LLDB_INVALID_ADDRESS) { |
| if (sign[0] == '+') |
| return addr + offset; |
| else |
| return addr - offset; |
| } |
| } |
| } |
| |
| if (error_ptr) { |
| error_set = true; |
| error_ptr->SetErrorStringWithFormat( |
| "address expression \"%s\" evaluation failed", s.str().c_str()); |
| } |
| } |
| |
| if (error_ptr) { |
| if (!error_set) |
| error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", |
| s.str().c_str()); |
| } |
| return fail_value; |
| } |