1//===-- OptionArgParser.cpp -----------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "lldb/Interpreter/OptionArgParser.h" 10#include "lldb/DataFormatters/FormatManager.h" 11#include "lldb/Target/ABI.h" 12#include "lldb/Target/Target.h" 13#include "lldb/Utility/Status.h" 14#include "lldb/Utility/StreamString.h" 15 16using namespace lldb_private; 17using namespace lldb; 18 19bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value, 20 bool *success_ptr) { 21 if (success_ptr) 22 *success_ptr = true; 23 ref = ref.trim(); 24 if (ref.equals_insensitive("false") || ref.equals_insensitive("off") || 25 ref.equals_insensitive("no") || ref.equals_insensitive("0")) { 26 return false; 27 } else if (ref.equals_insensitive("true") || ref.equals_insensitive("on") || 28 ref.equals_insensitive("yes") || ref.equals_insensitive("1")) { 29 return true; 30 } 31 if (success_ptr) 32 *success_ptr = false; 33 return fail_value; 34} 35 36char OptionArgParser::ToChar(llvm::StringRef s, char fail_value, 37 bool *success_ptr) { 38 if (success_ptr) 39 *success_ptr = false; 40 if (s.size() != 1) 41 return fail_value; 42 43 if (success_ptr) 44 *success_ptr = true; 45 return s[0]; 46} 47 48int64_t OptionArgParser::ToOptionEnum(llvm::StringRef s, 49 const OptionEnumValues &enum_values, 50 int32_t fail_value, Status &error) { 51 error.Clear(); 52 if (enum_values.empty()) { 53 error.SetErrorString("invalid enumeration argument"); 54 return fail_value; 55 } 56 57 if (s.empty()) { 58 error.SetErrorString("empty enumeration string"); 59 return fail_value; 60 } 61 62 for (const auto &enum_value : enum_values) { 63 llvm::StringRef this_enum(enum_value.string_value); 64 if (this_enum.starts_with(s)) 65 return enum_value.value; 66 } 67 68 StreamString strm; 69 strm.PutCString("invalid enumeration value, valid values are: "); 70 bool is_first = true; 71 for (const auto &enum_value : enum_values) { 72 strm.Printf("%s\"%s\"", 73 is_first ? is_first = false,"" : ", ", enum_value.string_value); 74 } 75 error.SetErrorString(strm.GetString()); 76 return fail_value; 77} 78 79Status OptionArgParser::ToFormat(const char *s, lldb::Format &format, 80 size_t *byte_size_ptr) { 81 format = eFormatInvalid; 82 Status error; 83 84 if (s && s[0]) { 85 if (byte_size_ptr) { 86 if (isdigit(s[0])) { 87 char *format_char = nullptr; 88 unsigned long byte_size = ::strtoul(s, &format_char, 0); 89 if (byte_size != ULONG_MAX) 90 *byte_size_ptr = byte_size; 91 s = format_char; 92 } else 93 *byte_size_ptr = 0; 94 } 95 96 const bool partial_match_ok = true; 97 if (!FormatManager::GetFormatFromCString(s, partial_match_ok, format)) { 98 StreamString error_strm; 99 error_strm.Printf( 100 "Invalid format character or name '%s'. Valid values are:\n", s); 101 for (Format f = eFormatDefault; f < kNumFormats; f = Format(f + 1)) { 102 char format_char = FormatManager::GetFormatAsFormatChar(f); 103 if (format_char) 104 error_strm.Printf("'%c' or ", format_char); 105 106 error_strm.Printf("\"%s\"", FormatManager::GetFormatAsCString(f)); 107 error_strm.EOL(); 108 } 109 110 if (byte_size_ptr) 111 error_strm.PutCString( 112 "An optional byte size can precede the format character.\n"); 113 error.SetErrorString(error_strm.GetString()); 114 } 115 116 if (error.Fail()) 117 return error; 118 } else { 119 error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid"); 120 } 121 return error; 122} 123 124lldb::ScriptLanguage OptionArgParser::ToScriptLanguage( 125 llvm::StringRef s, lldb::ScriptLanguage fail_value, bool *success_ptr) { 126 if (success_ptr) 127 *success_ptr = true; 128 129 if (s.equals_insensitive("python")) 130 return eScriptLanguagePython; 131 if (s.equals_insensitive("lua")) 132 return eScriptLanguageLua; 133 if (s.equals_insensitive("default")) 134 return eScriptLanguageDefault; 135 if (s.equals_insensitive("none")) 136 return eScriptLanguageNone; 137 138 if (success_ptr) 139 *success_ptr = false; 140 return fail_value; 141} 142 143lldb::addr_t OptionArgParser::ToRawAddress(const ExecutionContext *exe_ctx, 144 llvm::StringRef s, 145 lldb::addr_t fail_value, 146 Status *error_ptr) { 147 std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr); 148 return maybe_addr ? *maybe_addr : fail_value; 149} 150 151lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx, 152 llvm::StringRef s, 153 lldb::addr_t fail_value, 154 Status *error_ptr) { 155 std::optional<lldb::addr_t> maybe_addr = DoToAddress(exe_ctx, s, error_ptr); 156 if (!maybe_addr) 157 return fail_value; 158 159 lldb::addr_t addr = *maybe_addr; 160 161 if (Process *process = exe_ctx->GetProcessPtr()) 162 if (ABISP abi_sp = process->GetABI()) 163 addr = abi_sp->FixCodeAddress(addr); 164 165 return addr; 166} 167 168std::optional<lldb::addr_t> 169OptionArgParser::DoToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s, 170 Status *error_ptr) { 171 if (s.empty()) { 172 if (error_ptr) 173 error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", 174 s.str().c_str()); 175 return {}; 176 } 177 178 llvm::StringRef sref = s; 179 180 lldb::addr_t addr = LLDB_INVALID_ADDRESS; 181 if (!s.getAsInteger(0, addr)) { 182 if (error_ptr) 183 error_ptr->Clear(); 184 185 return addr; 186 } 187 188 // Try base 16 with no prefix... 189 if (!s.getAsInteger(16, addr)) { 190 if (error_ptr) 191 error_ptr->Clear(); 192 return addr; 193 } 194 195 Target *target = nullptr; 196 if (!exe_ctx || !(target = exe_ctx->GetTargetPtr())) { 197 if (error_ptr) 198 error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", 199 s.str().c_str()); 200 return {}; 201 } 202 203 lldb::ValueObjectSP valobj_sp; 204 EvaluateExpressionOptions options; 205 options.SetCoerceToId(false); 206 options.SetUnwindOnError(true); 207 options.SetKeepInMemory(false); 208 options.SetTryAllThreads(true); 209 210 ExpressionResults expr_result = 211 target->EvaluateExpression(s, exe_ctx->GetFramePtr(), valobj_sp, options); 212 213 bool success = false; 214 if (expr_result == eExpressionCompleted) { 215 if (valobj_sp) 216 valobj_sp = valobj_sp->GetQualifiedRepresentationIfAvailable( 217 valobj_sp->GetDynamicValueType(), true); 218 // Get the address to watch. 219 if (valobj_sp) 220 addr = valobj_sp->GetValueAsUnsigned(0, &success); 221 if (success) { 222 if (error_ptr) 223 error_ptr->Clear(); 224 return addr; 225 } 226 if (error_ptr) 227 error_ptr->SetErrorStringWithFormat( 228 "address expression \"%s\" resulted in a value whose type " 229 "can't be converted to an address: %s", 230 s.str().c_str(), valobj_sp->GetTypeName().GetCString()); 231 return {}; 232 } 233 234 // Since the compiler can't handle things like "main + 12" we should try to 235 // do this for now. The compiler doesn't like adding offsets to function 236 // pointer types. 237 static RegularExpression g_symbol_plus_offset_regex( 238 "^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); 239 240 llvm::SmallVector<llvm::StringRef, 4> matches; 241 if (g_symbol_plus_offset_regex.Execute(sref, &matches)) { 242 uint64_t offset = 0; 243 llvm::StringRef name = matches[1]; 244 llvm::StringRef sign = matches[2]; 245 llvm::StringRef str_offset = matches[3]; 246 if (!str_offset.getAsInteger(0, offset)) { 247 Status error; 248 addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error); 249 if (addr != LLDB_INVALID_ADDRESS) { 250 if (sign[0] == '+') 251 return addr + offset; 252 return addr - offset; 253 } 254 } 255 } 256 257 if (error_ptr) 258 error_ptr->SetErrorStringWithFormat( 259 "address expression \"%s\" evaluation failed", s.str().c_str()); 260 return {}; 261} 262