1 //===-- FormatEntity.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/Core/FormatEntity.h" 10 11 #include "lldb/Core/Address.h" 12 #include "lldb/Core/AddressRange.h" 13 #include "lldb/Core/Debugger.h" 14 #include "lldb/Core/DumpRegisterValue.h" 15 #include "lldb/Core/Module.h" 16 #include "lldb/Core/ValueObject.h" 17 #include "lldb/Core/ValueObjectVariable.h" 18 #include "lldb/DataFormatters/DataVisualization.h" 19 #include "lldb/DataFormatters/FormatClasses.h" 20 #include "lldb/DataFormatters/FormatManager.h" 21 #include "lldb/DataFormatters/TypeSummary.h" 22 #include "lldb/Expression/ExpressionVariable.h" 23 #include "lldb/Interpreter/CommandInterpreter.h" 24 #include "lldb/Symbol/Block.h" 25 #include "lldb/Symbol/CompileUnit.h" 26 #include "lldb/Symbol/CompilerType.h" 27 #include "lldb/Symbol/Function.h" 28 #include "lldb/Symbol/LineEntry.h" 29 #include "lldb/Symbol/Symbol.h" 30 #include "lldb/Symbol/SymbolContext.h" 31 #include "lldb/Symbol/VariableList.h" 32 #include "lldb/Target/ExecutionContext.h" 33 #include "lldb/Target/ExecutionContextScope.h" 34 #include "lldb/Target/Language.h" 35 #include "lldb/Target/Process.h" 36 #include "lldb/Target/RegisterContext.h" 37 #include "lldb/Target/SectionLoadList.h" 38 #include "lldb/Target/StackFrame.h" 39 #include "lldb/Target/StopInfo.h" 40 #include "lldb/Target/Target.h" 41 #include "lldb/Target/Thread.h" 42 #include "lldb/Utility/AnsiTerminal.h" 43 #include "lldb/Utility/ArchSpec.h" 44 #include "lldb/Utility/CompletionRequest.h" 45 #include "lldb/Utility/ConstString.h" 46 #include "lldb/Utility/FileSpec.h" 47 #include "lldb/Utility/LLDBLog.h" 48 #include "lldb/Utility/Log.h" 49 #include "lldb/Utility/RegisterValue.h" 50 #include "lldb/Utility/Status.h" 51 #include "lldb/Utility/Stream.h" 52 #include "lldb/Utility/StreamString.h" 53 #include "lldb/Utility/StringList.h" 54 #include "lldb/Utility/StructuredData.h" 55 #include "lldb/lldb-defines.h" 56 #include "lldb/lldb-forward.h" 57 #include "llvm/ADT/STLExtras.h" 58 #include "llvm/ADT/StringRef.h" 59 #include "llvm/Support/Compiler.h" 60 #include "llvm/Support/Regex.h" 61 #include "llvm/TargetParser/Triple.h" 62 63 #include <cctype> 64 #include <cinttypes> 65 #include <cstdio> 66 #include <cstdlib> 67 #include <cstring> 68 #include <memory> 69 #include <type_traits> 70 #include <utility> 71 72 namespace lldb_private { 73 class ScriptInterpreter; 74 } 75 namespace lldb_private { 76 struct RegisterInfo; 77 } 78 79 using namespace lldb; 80 using namespace lldb_private; 81 82 using Definition = lldb_private::FormatEntity::Entry::Definition; 83 using Entry = FormatEntity::Entry; 84 using EntryType = FormatEntity::Entry::Type; 85 86 enum FileKind { FileError = 0, Basename, Dirname, Fullpath }; 87 88 constexpr Definition g_string_entry[] = { 89 Definition("*", EntryType::ParentString)}; 90 91 constexpr Definition g_addr_entries[] = { 92 Definition("load", EntryType::AddressLoad), 93 Definition("file", EntryType::AddressFile)}; 94 95 constexpr Definition g_file_child_entries[] = { 96 Definition("basename", EntryType::ParentNumber, FileKind::Basename), 97 Definition("dirname", EntryType::ParentNumber, FileKind::Dirname), 98 Definition("fullpath", EntryType::ParentNumber, FileKind::Fullpath)}; 99 100 constexpr Definition g_frame_child_entries[] = { 101 Definition("index", EntryType::FrameIndex), 102 Definition("pc", EntryType::FrameRegisterPC), 103 Definition("fp", EntryType::FrameRegisterFP), 104 Definition("sp", EntryType::FrameRegisterSP), 105 Definition("flags", EntryType::FrameRegisterFlags), 106 Definition("no-debug", EntryType::FrameNoDebug), 107 Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName, 108 g_string_entry), 109 Definition("is-artificial", EntryType::FrameIsArtificial), 110 }; 111 112 constexpr Definition g_function_child_entries[] = { 113 Definition("id", EntryType::FunctionID), 114 Definition("name", EntryType::FunctionName), 115 Definition("name-without-args", EntryType::FunctionNameNoArgs), 116 Definition("name-with-args", EntryType::FunctionNameWithArgs), 117 Definition("mangled-name", EntryType::FunctionMangledName), 118 Definition("addr-offset", EntryType::FunctionAddrOffset), 119 Definition("concrete-only-addr-offset-no-padding", 120 EntryType::FunctionAddrOffsetConcrete), 121 Definition("line-offset", EntryType::FunctionLineOffset), 122 Definition("pc-offset", EntryType::FunctionPCOffset), 123 Definition("initial-function", EntryType::FunctionInitial), 124 Definition("changed", EntryType::FunctionChanged), 125 Definition("is-optimized", EntryType::FunctionIsOptimized)}; 126 127 constexpr Definition g_line_child_entries[] = { 128 Entry::DefinitionWithChildren("file", EntryType::LineEntryFile, 129 g_file_child_entries), 130 Definition("number", EntryType::LineEntryLineNumber), 131 Definition("column", EntryType::LineEntryColumn), 132 Definition("start-addr", EntryType::LineEntryStartAddress), 133 Definition("end-addr", EntryType::LineEntryEndAddress), 134 }; 135 136 constexpr Definition g_module_child_entries[] = {Entry::DefinitionWithChildren( 137 "file", EntryType::ModuleFile, g_file_child_entries)}; 138 139 constexpr Definition g_process_child_entries[] = { 140 Definition("id", EntryType::ProcessID), 141 Definition("name", EntryType::ProcessFile, FileKind::Basename), 142 Entry::DefinitionWithChildren("file", EntryType::ProcessFile, 143 g_file_child_entries)}; 144 145 constexpr Definition g_svar_child_entries[] = { 146 Definition("*", EntryType::ParentString)}; 147 148 constexpr Definition g_var_child_entries[] = { 149 Definition("*", EntryType::ParentString)}; 150 151 constexpr Definition g_thread_child_entries[] = { 152 Definition("id", EntryType::ThreadID), 153 Definition("protocol_id", EntryType::ThreadProtocolID), 154 Definition("index", EntryType::ThreadIndexID), 155 Entry::DefinitionWithChildren("info", EntryType::ThreadInfo, 156 g_string_entry), 157 Definition("queue", EntryType::ThreadQueue), 158 Definition("name", EntryType::ThreadName), 159 Definition("stop-reason", EntryType::ThreadStopReason), 160 Definition("stop-reason-raw", EntryType::ThreadStopReasonRaw), 161 Definition("return-value", EntryType::ThreadReturnValue), 162 Definition("completed-expression", EntryType::ThreadCompletedExpression)}; 163 164 constexpr Definition g_target_child_entries[] = { 165 Definition("arch", EntryType::TargetArch)}; 166 167 #define _TO_STR2(_val) #_val 168 #define _TO_STR(_val) _TO_STR2(_val) 169 170 constexpr Definition g_ansi_fg_entries[] = { 171 Definition("black", 172 ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END), 173 Definition("red", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END), 174 Definition("green", 175 ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END), 176 Definition("yellow", 177 ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END), 178 Definition("blue", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END), 179 Definition("purple", 180 ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END), 181 Definition("cyan", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END), 182 Definition("white", 183 ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END), 184 }; 185 186 constexpr Definition g_ansi_bg_entries[] = { 187 Definition("black", 188 ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END), 189 Definition("red", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END), 190 Definition("green", 191 ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END), 192 Definition("yellow", 193 ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END), 194 Definition("blue", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END), 195 Definition("purple", 196 ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END), 197 Definition("cyan", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END), 198 Definition("white", 199 ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END), 200 }; 201 202 constexpr Definition g_ansi_entries[] = { 203 Entry::DefinitionWithChildren("fg", EntryType::Invalid, g_ansi_fg_entries), 204 Entry::DefinitionWithChildren("bg", EntryType::Invalid, g_ansi_bg_entries), 205 Definition("normal", ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END), 206 Definition("bold", ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END), 207 Definition("faint", ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END), 208 Definition("italic", ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END), 209 Definition("underline", 210 ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END), 211 Definition("slow-blink", 212 ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END), 213 Definition("fast-blink", 214 ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END), 215 Definition("negative", 216 ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END), 217 Definition("conceal", 218 ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END), 219 Definition("crossed-out", 220 ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END), 221 }; 222 223 constexpr Definition g_script_child_entries[] = { 224 Definition("frame", EntryType::ScriptFrame), 225 Definition("process", EntryType::ScriptProcess), 226 Definition("target", EntryType::ScriptTarget), 227 Definition("thread", EntryType::ScriptThread), 228 Definition("var", EntryType::ScriptVariable), 229 Definition("svar", EntryType::ScriptVariableSynthetic), 230 Definition("thread", EntryType::ScriptThread)}; 231 232 constexpr Definition g_top_level_entries[] = { 233 Entry::DefinitionWithChildren("addr", EntryType::AddressLoadOrFile, 234 g_addr_entries), 235 Definition("addr-file-or-load", EntryType::AddressLoadOrFile), 236 Entry::DefinitionWithChildren("ansi", EntryType::Invalid, g_ansi_entries), 237 Definition("current-pc-arrow", EntryType::CurrentPCArrow), 238 Entry::DefinitionWithChildren("file", EntryType::File, 239 g_file_child_entries), 240 Definition("language", EntryType::Lang), 241 Entry::DefinitionWithChildren("frame", EntryType::Invalid, 242 g_frame_child_entries), 243 Entry::DefinitionWithChildren("function", EntryType::Invalid, 244 g_function_child_entries), 245 Entry::DefinitionWithChildren("line", EntryType::Invalid, 246 g_line_child_entries), 247 Entry::DefinitionWithChildren("module", EntryType::Invalid, 248 g_module_child_entries), 249 Entry::DefinitionWithChildren("process", EntryType::Invalid, 250 g_process_child_entries), 251 Entry::DefinitionWithChildren("script", EntryType::Invalid, 252 g_script_child_entries), 253 Entry::DefinitionWithChildren("svar", EntryType::VariableSynthetic, 254 g_svar_child_entries, true), 255 Entry::DefinitionWithChildren("thread", EntryType::Invalid, 256 g_thread_child_entries), 257 Entry::DefinitionWithChildren("target", EntryType::Invalid, 258 g_target_child_entries), 259 Entry::DefinitionWithChildren("var", EntryType::Variable, 260 g_var_child_entries, true)}; 261 262 constexpr Definition g_root = Entry::DefinitionWithChildren( 263 "<root>", EntryType::Root, g_top_level_entries); 264 265 FormatEntity::Entry::Entry(llvm::StringRef s) 266 : string(s.data(), s.size()), printf_format(), children(), 267 type(Type::String) {} 268 269 FormatEntity::Entry::Entry(char ch) 270 : string(1, ch), printf_format(), children(), type(Type::String) {} 271 272 void FormatEntity::Entry::AppendChar(char ch) { 273 if (children.empty() || children.back().type != Entry::Type::String) 274 children.push_back(Entry(ch)); 275 else 276 children.back().string.append(1, ch); 277 } 278 279 void FormatEntity::Entry::AppendText(const llvm::StringRef &s) { 280 if (children.empty() || children.back().type != Entry::Type::String) 281 children.push_back(Entry(s)); 282 else 283 children.back().string.append(s.data(), s.size()); 284 } 285 286 void FormatEntity::Entry::AppendText(const char *cstr) { 287 return AppendText(llvm::StringRef(cstr)); 288 } 289 290 #define ENUM_TO_CSTR(eee) \ 291 case FormatEntity::Entry::Type::eee: \ 292 return #eee 293 294 const char *FormatEntity::Entry::TypeToCString(Type t) { 295 switch (t) { 296 ENUM_TO_CSTR(Invalid); 297 ENUM_TO_CSTR(ParentNumber); 298 ENUM_TO_CSTR(ParentString); 299 ENUM_TO_CSTR(EscapeCode); 300 ENUM_TO_CSTR(Root); 301 ENUM_TO_CSTR(String); 302 ENUM_TO_CSTR(Scope); 303 ENUM_TO_CSTR(Variable); 304 ENUM_TO_CSTR(VariableSynthetic); 305 ENUM_TO_CSTR(ScriptVariable); 306 ENUM_TO_CSTR(ScriptVariableSynthetic); 307 ENUM_TO_CSTR(AddressLoad); 308 ENUM_TO_CSTR(AddressFile); 309 ENUM_TO_CSTR(AddressLoadOrFile); 310 ENUM_TO_CSTR(ProcessID); 311 ENUM_TO_CSTR(ProcessFile); 312 ENUM_TO_CSTR(ScriptProcess); 313 ENUM_TO_CSTR(ThreadID); 314 ENUM_TO_CSTR(ThreadProtocolID); 315 ENUM_TO_CSTR(ThreadIndexID); 316 ENUM_TO_CSTR(ThreadName); 317 ENUM_TO_CSTR(ThreadQueue); 318 ENUM_TO_CSTR(ThreadStopReason); 319 ENUM_TO_CSTR(ThreadStopReasonRaw); 320 ENUM_TO_CSTR(ThreadReturnValue); 321 ENUM_TO_CSTR(ThreadCompletedExpression); 322 ENUM_TO_CSTR(ScriptThread); 323 ENUM_TO_CSTR(ThreadInfo); 324 ENUM_TO_CSTR(TargetArch); 325 ENUM_TO_CSTR(ScriptTarget); 326 ENUM_TO_CSTR(ModuleFile); 327 ENUM_TO_CSTR(File); 328 ENUM_TO_CSTR(Lang); 329 ENUM_TO_CSTR(FrameIndex); 330 ENUM_TO_CSTR(FrameNoDebug); 331 ENUM_TO_CSTR(FrameRegisterPC); 332 ENUM_TO_CSTR(FrameRegisterSP); 333 ENUM_TO_CSTR(FrameRegisterFP); 334 ENUM_TO_CSTR(FrameRegisterFlags); 335 ENUM_TO_CSTR(FrameRegisterByName); 336 ENUM_TO_CSTR(FrameIsArtificial); 337 ENUM_TO_CSTR(ScriptFrame); 338 ENUM_TO_CSTR(FunctionID); 339 ENUM_TO_CSTR(FunctionDidChange); 340 ENUM_TO_CSTR(FunctionInitialFunction); 341 ENUM_TO_CSTR(FunctionName); 342 ENUM_TO_CSTR(FunctionNameWithArgs); 343 ENUM_TO_CSTR(FunctionNameNoArgs); 344 ENUM_TO_CSTR(FunctionMangledName); 345 ENUM_TO_CSTR(FunctionAddrOffset); 346 ENUM_TO_CSTR(FunctionAddrOffsetConcrete); 347 ENUM_TO_CSTR(FunctionLineOffset); 348 ENUM_TO_CSTR(FunctionPCOffset); 349 ENUM_TO_CSTR(FunctionInitial); 350 ENUM_TO_CSTR(FunctionChanged); 351 ENUM_TO_CSTR(FunctionIsOptimized); 352 ENUM_TO_CSTR(LineEntryFile); 353 ENUM_TO_CSTR(LineEntryLineNumber); 354 ENUM_TO_CSTR(LineEntryColumn); 355 ENUM_TO_CSTR(LineEntryStartAddress); 356 ENUM_TO_CSTR(LineEntryEndAddress); 357 ENUM_TO_CSTR(CurrentPCArrow); 358 } 359 return "???"; 360 } 361 362 #undef ENUM_TO_CSTR 363 364 void FormatEntity::Entry::Dump(Stream &s, int depth) const { 365 s.Printf("%*.*s%-20s: ", depth * 2, depth * 2, "", TypeToCString(type)); 366 if (fmt != eFormatDefault) 367 s.Printf("lldb-format = %s, ", FormatManager::GetFormatAsCString(fmt)); 368 if (!string.empty()) 369 s.Printf("string = \"%s\"", string.c_str()); 370 if (!printf_format.empty()) 371 s.Printf("printf_format = \"%s\"", printf_format.c_str()); 372 if (number != 0) 373 s.Printf("number = %" PRIu64 " (0x%" PRIx64 "), ", number, number); 374 if (deref) 375 s.Printf("deref = true, "); 376 s.EOL(); 377 for (const auto &child : children) { 378 child.Dump(s, depth + 1); 379 } 380 } 381 382 template <typename T> 383 static bool RunScriptFormatKeyword(Stream &s, const SymbolContext *sc, 384 const ExecutionContext *exe_ctx, T t, 385 const char *script_function_name) { 386 Target *target = Target::GetTargetFromContexts(exe_ctx, sc); 387 388 if (target) { 389 ScriptInterpreter *script_interpreter = 390 target->GetDebugger().GetScriptInterpreter(); 391 if (script_interpreter) { 392 Status error; 393 std::string script_output; 394 395 if (script_interpreter->RunScriptFormatKeyword(script_function_name, t, 396 script_output, error) && 397 error.Success()) { 398 s.Printf("%s", script_output.c_str()); 399 return true; 400 } else { 401 s.Printf("<error: %s>", error.AsCString()); 402 } 403 } 404 } 405 return false; 406 } 407 408 static bool DumpAddressAndContent(Stream &s, const SymbolContext *sc, 409 const ExecutionContext *exe_ctx, 410 const Address &addr, 411 bool print_file_addr_or_load_addr) { 412 Target *target = Target::GetTargetFromContexts(exe_ctx, sc); 413 addr_t vaddr = LLDB_INVALID_ADDRESS; 414 if (exe_ctx && !target->GetSectionLoadList().IsEmpty()) 415 vaddr = addr.GetLoadAddress(target); 416 if (vaddr == LLDB_INVALID_ADDRESS) 417 vaddr = addr.GetFileAddress(); 418 419 if (vaddr != LLDB_INVALID_ADDRESS) { 420 int addr_width = 0; 421 if (exe_ctx && target) { 422 addr_width = target->GetArchitecture().GetAddressByteSize() * 2; 423 } 424 if (addr_width == 0) 425 addr_width = 16; 426 if (print_file_addr_or_load_addr) { 427 ExecutionContextScope *exe_scope = nullptr; 428 if (exe_ctx) 429 exe_scope = exe_ctx->GetBestExecutionContextScope(); 430 addr.Dump(&s, exe_scope, Address::DumpStyleLoadAddress, 431 Address::DumpStyleModuleWithFileAddress, 0); 432 } else { 433 s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr); 434 } 435 return true; 436 } 437 return false; 438 } 439 440 static bool DumpAddressOffsetFromFunction(Stream &s, const SymbolContext *sc, 441 const ExecutionContext *exe_ctx, 442 const Address &format_addr, 443 bool concrete_only, bool no_padding, 444 bool print_zero_offsets) { 445 if (format_addr.IsValid()) { 446 Address func_addr; 447 448 if (sc) { 449 if (sc->function) { 450 func_addr = sc->function->GetAddressRange().GetBaseAddress(); 451 if (sc->block && !concrete_only) { 452 // Check to make sure we aren't in an inline function. If we are, use 453 // the inline block range that contains "format_addr" since blocks 454 // can be discontiguous. 455 Block *inline_block = sc->block->GetContainingInlinedBlock(); 456 AddressRange inline_range; 457 if (inline_block && inline_block->GetRangeContainingAddress( 458 format_addr, inline_range)) 459 func_addr = inline_range.GetBaseAddress(); 460 } 461 } else if (sc->symbol && sc->symbol->ValueIsAddress()) 462 func_addr = sc->symbol->GetAddressRef(); 463 } 464 465 if (func_addr.IsValid()) { 466 const char *addr_offset_padding = no_padding ? "" : " "; 467 468 if (func_addr.GetSection() == format_addr.GetSection()) { 469 addr_t func_file_addr = func_addr.GetFileAddress(); 470 addr_t addr_file_addr = format_addr.GetFileAddress(); 471 if (addr_file_addr > func_file_addr || 472 (addr_file_addr == func_file_addr && print_zero_offsets)) { 473 s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, 474 addr_file_addr - func_file_addr); 475 } else if (addr_file_addr < func_file_addr) { 476 s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, 477 func_file_addr - addr_file_addr); 478 } 479 return true; 480 } else { 481 Target *target = Target::GetTargetFromContexts(exe_ctx, sc); 482 if (target) { 483 addr_t func_load_addr = func_addr.GetLoadAddress(target); 484 addr_t addr_load_addr = format_addr.GetLoadAddress(target); 485 if (addr_load_addr > func_load_addr || 486 (addr_load_addr == func_load_addr && print_zero_offsets)) { 487 s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, 488 addr_load_addr - func_load_addr); 489 } else if (addr_load_addr < func_load_addr) { 490 s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, 491 func_load_addr - addr_load_addr); 492 } 493 return true; 494 } 495 } 496 } 497 } 498 return false; 499 } 500 501 static bool ScanBracketedRange(llvm::StringRef subpath, 502 size_t &close_bracket_index, 503 const char *&var_name_final_if_array_range, 504 int64_t &index_lower, int64_t &index_higher) { 505 Log *log = GetLog(LLDBLog::DataFormatters); 506 close_bracket_index = llvm::StringRef::npos; 507 const size_t open_bracket_index = subpath.find('['); 508 if (open_bracket_index == llvm::StringRef::npos) { 509 LLDB_LOGF(log, 510 "[ScanBracketedRange] no bracketed range, skipping entirely"); 511 return false; 512 } 513 514 close_bracket_index = subpath.find(']', open_bracket_index + 1); 515 516 if (close_bracket_index == llvm::StringRef::npos) { 517 LLDB_LOGF(log, 518 "[ScanBracketedRange] no bracketed range, skipping entirely"); 519 return false; 520 } else { 521 var_name_final_if_array_range = subpath.data() + open_bracket_index; 522 523 if (close_bracket_index - open_bracket_index == 1) { 524 LLDB_LOGF( 525 log, 526 "[ScanBracketedRange] '[]' detected.. going from 0 to end of data"); 527 index_lower = 0; 528 } else { 529 const size_t separator_index = subpath.find('-', open_bracket_index + 1); 530 531 if (separator_index == llvm::StringRef::npos) { 532 const char *index_lower_cstr = subpath.data() + open_bracket_index + 1; 533 index_lower = ::strtoul(index_lower_cstr, nullptr, 0); 534 index_higher = index_lower; 535 LLDB_LOGF(log, 536 "[ScanBracketedRange] [%" PRId64 537 "] detected, high index is same", 538 index_lower); 539 } else { 540 const char *index_lower_cstr = subpath.data() + open_bracket_index + 1; 541 const char *index_higher_cstr = subpath.data() + separator_index + 1; 542 index_lower = ::strtoul(index_lower_cstr, nullptr, 0); 543 index_higher = ::strtoul(index_higher_cstr, nullptr, 0); 544 LLDB_LOGF(log, 545 "[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", 546 index_lower, index_higher); 547 } 548 if (index_lower > index_higher && index_higher > 0) { 549 LLDB_LOGF(log, "[ScanBracketedRange] swapping indices"); 550 const int64_t temp = index_lower; 551 index_lower = index_higher; 552 index_higher = temp; 553 } 554 } 555 } 556 return true; 557 } 558 559 static bool DumpFile(Stream &s, const FileSpec &file, FileKind file_kind) { 560 switch (file_kind) { 561 case FileKind::FileError: 562 break; 563 564 case FileKind::Basename: 565 if (file.GetFilename()) { 566 s << file.GetFilename(); 567 return true; 568 } 569 break; 570 571 case FileKind::Dirname: 572 if (file.GetDirectory()) { 573 s << file.GetDirectory(); 574 return true; 575 } 576 break; 577 578 case FileKind::Fullpath: 579 if (file) { 580 s << file; 581 return true; 582 } 583 break; 584 } 585 return false; 586 } 587 588 static bool DumpRegister(Stream &s, StackFrame *frame, RegisterKind reg_kind, 589 uint32_t reg_num, Format format) { 590 if (frame) { 591 RegisterContext *reg_ctx = frame->GetRegisterContext().get(); 592 593 if (reg_ctx) { 594 const uint32_t lldb_reg_num = 595 reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); 596 if (lldb_reg_num != LLDB_INVALID_REGNUM) { 597 const RegisterInfo *reg_info = 598 reg_ctx->GetRegisterInfoAtIndex(lldb_reg_num); 599 if (reg_info) { 600 RegisterValue reg_value; 601 if (reg_ctx->ReadRegister(reg_info, reg_value)) { 602 DumpRegisterValue(reg_value, s, *reg_info, false, false, format); 603 return true; 604 } 605 } 606 } 607 } 608 } 609 return false; 610 } 611 612 static ValueObjectSP ExpandIndexedExpression(ValueObject *valobj, size_t index, 613 bool deref_pointer) { 614 Log *log = GetLog(LLDBLog::DataFormatters); 615 std::string name_to_deref = llvm::formatv("[{0}]", index); 616 LLDB_LOG(log, "[ExpandIndexedExpression] name to deref: {0}", name_to_deref); 617 ValueObject::GetValueForExpressionPathOptions options; 618 ValueObject::ExpressionPathEndResultType final_value_type; 619 ValueObject::ExpressionPathScanEndReason reason_to_stop; 620 ValueObject::ExpressionPathAftermath what_next = 621 (deref_pointer ? ValueObject::eExpressionPathAftermathDereference 622 : ValueObject::eExpressionPathAftermathNothing); 623 ValueObjectSP item = valobj->GetValueForExpressionPath( 624 name_to_deref, &reason_to_stop, &final_value_type, options, &what_next); 625 if (!item) { 626 LLDB_LOGF(log, 627 "[ExpandIndexedExpression] ERROR: why stopping = %d," 628 " final_value_type %d", 629 reason_to_stop, final_value_type); 630 } else { 631 LLDB_LOGF(log, 632 "[ExpandIndexedExpression] ALL RIGHT: why stopping = %d," 633 " final_value_type %d", 634 reason_to_stop, final_value_type); 635 } 636 return item; 637 } 638 639 static char ConvertValueObjectStyleToChar( 640 ValueObject::ValueObjectRepresentationStyle style) { 641 switch (style) { 642 case ValueObject::eValueObjectRepresentationStyleLanguageSpecific: 643 return '@'; 644 case ValueObject::eValueObjectRepresentationStyleValue: 645 return 'V'; 646 case ValueObject::eValueObjectRepresentationStyleLocation: 647 return 'L'; 648 case ValueObject::eValueObjectRepresentationStyleSummary: 649 return 'S'; 650 case ValueObject::eValueObjectRepresentationStyleChildrenCount: 651 return '#'; 652 case ValueObject::eValueObjectRepresentationStyleType: 653 return 'T'; 654 case ValueObject::eValueObjectRepresentationStyleName: 655 return 'N'; 656 case ValueObject::eValueObjectRepresentationStyleExpressionPath: 657 return '>'; 658 } 659 return '\0'; 660 } 661 662 /// Options supported by format_provider<T> for integral arithmetic types. 663 /// See table in FormatProviders.h. 664 static llvm::Regex LLVMFormatPattern{"x[-+]?\\d*|n|d", llvm::Regex::IgnoreCase}; 665 666 static bool DumpValueWithLLVMFormat(Stream &s, llvm::StringRef options, 667 ValueObject &valobj) { 668 std::string formatted; 669 std::string llvm_format = ("{0:" + options + "}").str(); 670 671 auto type_info = valobj.GetTypeInfo(); 672 if ((type_info & eTypeIsInteger) && LLVMFormatPattern.match(options)) { 673 if (type_info & eTypeIsSigned) { 674 bool success = false; 675 int64_t integer = valobj.GetValueAsSigned(0, &success); 676 if (success) 677 formatted = llvm::formatv(llvm_format.data(), integer); 678 } else { 679 bool success = false; 680 uint64_t integer = valobj.GetValueAsUnsigned(0, &success); 681 if (success) 682 formatted = llvm::formatv(llvm_format.data(), integer); 683 } 684 } 685 686 if (formatted.empty()) 687 return false; 688 689 s.Write(formatted.data(), formatted.size()); 690 return true; 691 } 692 693 static bool DumpValue(Stream &s, const SymbolContext *sc, 694 const ExecutionContext *exe_ctx, 695 const FormatEntity::Entry &entry, ValueObject *valobj) { 696 if (valobj == nullptr) 697 return false; 698 699 Log *log = GetLog(LLDBLog::DataFormatters); 700 Format custom_format = eFormatInvalid; 701 ValueObject::ValueObjectRepresentationStyle val_obj_display = 702 entry.string.empty() 703 ? ValueObject::eValueObjectRepresentationStyleValue 704 : ValueObject::eValueObjectRepresentationStyleSummary; 705 706 bool do_deref_pointer = entry.deref; 707 bool is_script = false; 708 switch (entry.type) { 709 case FormatEntity::Entry::Type::ScriptVariable: 710 is_script = true; 711 break; 712 713 case FormatEntity::Entry::Type::Variable: 714 custom_format = entry.fmt; 715 val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number; 716 break; 717 718 case FormatEntity::Entry::Type::ScriptVariableSynthetic: 719 is_script = true; 720 [[fallthrough]]; 721 case FormatEntity::Entry::Type::VariableSynthetic: 722 custom_format = entry.fmt; 723 val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number; 724 if (!valobj->IsSynthetic()) { 725 valobj = valobj->GetSyntheticValue().get(); 726 if (valobj == nullptr) 727 return false; 728 } 729 break; 730 731 default: 732 return false; 733 } 734 735 ValueObject::ExpressionPathAftermath what_next = 736 (do_deref_pointer ? ValueObject::eExpressionPathAftermathDereference 737 : ValueObject::eExpressionPathAftermathNothing); 738 ValueObject::GetValueForExpressionPathOptions options; 739 options.DontCheckDotVsArrowSyntax() 740 .DoAllowBitfieldSyntax() 741 .DoAllowFragileIVar() 742 .SetSyntheticChildrenTraversal( 743 ValueObject::GetValueForExpressionPathOptions:: 744 SyntheticChildrenTraversal::Both); 745 ValueObject *target = nullptr; 746 const char *var_name_final_if_array_range = nullptr; 747 size_t close_bracket_index = llvm::StringRef::npos; 748 int64_t index_lower = -1; 749 int64_t index_higher = -1; 750 bool is_array_range = false; 751 bool was_plain_var = false; 752 bool was_var_format = false; 753 bool was_var_indexed = false; 754 ValueObject::ExpressionPathScanEndReason reason_to_stop = 755 ValueObject::eExpressionPathScanEndReasonEndOfString; 756 ValueObject::ExpressionPathEndResultType final_value_type = 757 ValueObject::eExpressionPathEndResultTypePlain; 758 759 if (is_script) { 760 return RunScriptFormatKeyword(s, sc, exe_ctx, valobj, entry.string.c_str()); 761 } 762 763 auto split = llvm::StringRef(entry.string).split(':'); 764 auto subpath = split.first; 765 auto llvm_format = split.second; 766 767 // simplest case ${var}, just print valobj's value 768 if (subpath.empty()) { 769 if (entry.printf_format.empty() && entry.fmt == eFormatDefault && 770 entry.number == ValueObject::eValueObjectRepresentationStyleValue) 771 was_plain_var = true; 772 else 773 was_var_format = true; 774 target = valobj; 775 } else // this is ${var.something} or multiple .something nested 776 { 777 if (subpath[0] == '[') 778 was_var_indexed = true; 779 ScanBracketedRange(subpath, close_bracket_index, 780 var_name_final_if_array_range, index_lower, 781 index_higher); 782 783 Status error; 784 785 LLDB_LOG(log, "[Debugger::FormatPrompt] symbol to expand: {0}", subpath); 786 787 target = 788 valobj 789 ->GetValueForExpressionPath(subpath, &reason_to_stop, 790 &final_value_type, options, &what_next) 791 .get(); 792 793 if (!target) { 794 LLDB_LOGF(log, 795 "[Debugger::FormatPrompt] ERROR: why stopping = %d," 796 " final_value_type %d", 797 reason_to_stop, final_value_type); 798 return false; 799 } else { 800 LLDB_LOGF(log, 801 "[Debugger::FormatPrompt] ALL RIGHT: why stopping = %d," 802 " final_value_type %d", 803 reason_to_stop, final_value_type); 804 target = target 805 ->GetQualifiedRepresentationIfAvailable( 806 target->GetDynamicValueType(), true) 807 .get(); 808 } 809 } 810 811 is_array_range = 812 (final_value_type == 813 ValueObject::eExpressionPathEndResultTypeBoundedRange || 814 final_value_type == 815 ValueObject::eExpressionPathEndResultTypeUnboundedRange); 816 817 do_deref_pointer = 818 (what_next == ValueObject::eExpressionPathAftermathDereference); 819 820 if (do_deref_pointer && !is_array_range) { 821 // I have not deref-ed yet, let's do it 822 // this happens when we are not going through 823 // GetValueForVariableExpressionPath to get to the target ValueObject 824 Status error; 825 target = target->Dereference(error).get(); 826 if (error.Fail()) { 827 LLDB_LOGF(log, "[Debugger::FormatPrompt] ERROR: %s\n", 828 error.AsCString("unknown")); 829 return false; 830 } 831 do_deref_pointer = false; 832 } 833 834 if (!target) { 835 LLDB_LOGF(log, "[Debugger::FormatPrompt] could not calculate target for " 836 "prompt expression"); 837 return false; 838 } 839 840 // we do not want to use the summary for a bitfield of type T:n if we were 841 // originally dealing with just a T - that would get us into an endless 842 // recursion 843 if (target->IsBitfield() && was_var_indexed) { 844 // TODO: check for a (T:n)-specific summary - we should still obey that 845 StreamString bitfield_name; 846 bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), 847 target->GetBitfieldBitSize()); 848 auto type_sp = std::make_shared<TypeNameSpecifierImpl>( 849 bitfield_name.GetString(), lldb::eFormatterMatchExact); 850 if (val_obj_display == 851 ValueObject::eValueObjectRepresentationStyleSummary && 852 !DataVisualization::GetSummaryForType(type_sp)) 853 val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 854 } 855 856 // TODO use flags for these 857 const uint32_t type_info_flags = 858 target->GetCompilerType().GetTypeInfo(nullptr); 859 bool is_array = (type_info_flags & eTypeIsArray) != 0; 860 bool is_pointer = (type_info_flags & eTypeIsPointer) != 0; 861 bool is_aggregate = target->GetCompilerType().IsAggregateType(); 862 863 if ((is_array || is_pointer) && (!is_array_range) && 864 val_obj_display == 865 ValueObject::eValueObjectRepresentationStyleValue) // this should be 866 // wrong, but there 867 // are some 868 // exceptions 869 { 870 StreamString str_temp; 871 LLDB_LOGF(log, 872 "[Debugger::FormatPrompt] I am into array || pointer && !range"); 873 874 if (target->HasSpecialPrintableRepresentation(val_obj_display, 875 custom_format)) { 876 // try to use the special cases 877 bool success = target->DumpPrintableRepresentation( 878 str_temp, val_obj_display, custom_format); 879 LLDB_LOGF(log, "[Debugger::FormatPrompt] special cases did%s match", 880 success ? "" : "n't"); 881 882 // should not happen 883 if (success) 884 s << str_temp.GetString(); 885 return true; 886 } else { 887 if (was_plain_var) // if ${var} 888 { 889 s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); 890 } else if (is_pointer) // if pointer, value is the address stored 891 { 892 target->DumpPrintableRepresentation( 893 s, val_obj_display, custom_format, 894 ValueObject::PrintableRepresentationSpecialCases::eDisable); 895 } 896 return true; 897 } 898 } 899 900 // if directly trying to print ${var}, and this is an aggregate, display a 901 // nice type @ location message 902 if (is_aggregate && was_plain_var) { 903 s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); 904 return true; 905 } 906 907 // if directly trying to print ${var%V}, and this is an aggregate, do not let 908 // the user do it 909 if (is_aggregate && 910 ((was_var_format && 911 val_obj_display == 912 ValueObject::eValueObjectRepresentationStyleValue))) { 913 s << "<invalid use of aggregate type>"; 914 return true; 915 } 916 917 if (!is_array_range) { 918 if (!llvm_format.empty()) { 919 if (DumpValueWithLLVMFormat(s, llvm_format, *target)) { 920 LLDB_LOGF(log, "dumping using llvm format"); 921 return true; 922 } else { 923 LLDB_LOG( 924 log, 925 "empty output using llvm format '{0}' - with type info flags {1}", 926 entry.printf_format, target->GetTypeInfo()); 927 } 928 } 929 LLDB_LOGF(log, "dumping ordinary printable output"); 930 return target->DumpPrintableRepresentation(s, val_obj_display, 931 custom_format); 932 } else { 933 LLDB_LOGF(log, 934 "[Debugger::FormatPrompt] checking if I can handle as array"); 935 if (!is_array && !is_pointer) 936 return false; 937 LLDB_LOGF(log, "[Debugger::FormatPrompt] handle as array"); 938 StreamString special_directions_stream; 939 llvm::StringRef special_directions; 940 if (close_bracket_index != llvm::StringRef::npos && 941 subpath.size() > close_bracket_index) { 942 ConstString additional_data(subpath.drop_front(close_bracket_index + 1)); 943 special_directions_stream.Printf("${%svar%s", do_deref_pointer ? "*" : "", 944 additional_data.GetCString()); 945 946 if (entry.fmt != eFormatDefault) { 947 const char format_char = 948 FormatManager::GetFormatAsFormatChar(entry.fmt); 949 if (format_char != '\0') 950 special_directions_stream.Printf("%%%c", format_char); 951 else { 952 const char *format_cstr = 953 FormatManager::GetFormatAsCString(entry.fmt); 954 special_directions_stream.Printf("%%%s", format_cstr); 955 } 956 } else if (entry.number != 0) { 957 const char style_char = ConvertValueObjectStyleToChar( 958 (ValueObject::ValueObjectRepresentationStyle)entry.number); 959 if (style_char) 960 special_directions_stream.Printf("%%%c", style_char); 961 } 962 special_directions_stream.PutChar('}'); 963 special_directions = 964 llvm::StringRef(special_directions_stream.GetString()); 965 } 966 967 // let us display items index_lower thru index_higher of this array 968 s.PutChar('['); 969 970 if (index_higher < 0) 971 index_higher = valobj->GetNumChildrenIgnoringErrors() - 1; 972 973 uint32_t max_num_children = 974 target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 975 976 bool success = true; 977 for (int64_t index = index_lower; index <= index_higher; ++index) { 978 ValueObject *item = ExpandIndexedExpression(target, index, false).get(); 979 980 if (!item) { 981 LLDB_LOGF(log, 982 "[Debugger::FormatPrompt] ERROR in getting child item at " 983 "index %" PRId64, 984 index); 985 } else { 986 LLDB_LOGF( 987 log, 988 "[Debugger::FormatPrompt] special_directions for child item: %s", 989 special_directions.data() ? special_directions.data() : ""); 990 } 991 992 if (special_directions.empty()) { 993 success &= item->DumpPrintableRepresentation(s, val_obj_display, 994 custom_format); 995 } else { 996 success &= FormatEntity::FormatStringRef( 997 special_directions, s, sc, exe_ctx, nullptr, item, false, false); 998 } 999 1000 if (--max_num_children == 0) { 1001 s.PutCString(", ..."); 1002 break; 1003 } 1004 1005 if (index < index_higher) 1006 s.PutChar(','); 1007 } 1008 s.PutChar(']'); 1009 return success; 1010 } 1011 } 1012 1013 static bool DumpRegister(Stream &s, StackFrame *frame, const char *reg_name, 1014 Format format) { 1015 if (frame) { 1016 RegisterContext *reg_ctx = frame->GetRegisterContext().get(); 1017 1018 if (reg_ctx) { 1019 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 1020 if (reg_info) { 1021 RegisterValue reg_value; 1022 if (reg_ctx->ReadRegister(reg_info, reg_value)) { 1023 DumpRegisterValue(reg_value, s, *reg_info, false, false, format); 1024 return true; 1025 } 1026 } 1027 } 1028 } 1029 return false; 1030 } 1031 1032 static bool FormatThreadExtendedInfoRecurse( 1033 const FormatEntity::Entry &entry, 1034 const StructuredData::ObjectSP &thread_info_dictionary, 1035 const SymbolContext *sc, const ExecutionContext *exe_ctx, Stream &s) { 1036 llvm::StringRef path(entry.string); 1037 1038 StructuredData::ObjectSP value = 1039 thread_info_dictionary->GetObjectForDotSeparatedPath(path); 1040 1041 if (value) { 1042 if (value->GetType() == eStructuredDataTypeInteger) { 1043 const char *token_format = "0x%4.4" PRIx64; 1044 if (!entry.printf_format.empty()) 1045 token_format = entry.printf_format.c_str(); 1046 s.Printf(token_format, value->GetUnsignedIntegerValue()); 1047 return true; 1048 } else if (value->GetType() == eStructuredDataTypeFloat) { 1049 s.Printf("%f", value->GetAsFloat()->GetValue()); 1050 return true; 1051 } else if (value->GetType() == eStructuredDataTypeString) { 1052 s.Format("{0}", value->GetAsString()->GetValue()); 1053 return true; 1054 } else if (value->GetType() == eStructuredDataTypeArray) { 1055 if (value->GetAsArray()->GetSize() > 0) { 1056 s.Printf("%zu", value->GetAsArray()->GetSize()); 1057 return true; 1058 } 1059 } else if (value->GetType() == eStructuredDataTypeDictionary) { 1060 s.Printf("%zu", 1061 value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); 1062 return true; 1063 } 1064 } 1065 1066 return false; 1067 } 1068 1069 static inline bool IsToken(const char *var_name_begin, const char *var) { 1070 return (::strncmp(var_name_begin, var, strlen(var)) == 0); 1071 } 1072 1073 /// Parses the basename out of a demangled function name 1074 /// that may include function arguments. Supports 1075 /// template functions. 1076 /// 1077 /// Returns pointers to the opening and closing parenthesis of 1078 /// `full_name`. Can return nullptr for either parenthesis if 1079 /// none is exists. 1080 static std::pair<char const *, char const *> 1081 ParseBaseName(char const *full_name) { 1082 const char *open_paren = strchr(full_name, '('); 1083 const char *close_paren = nullptr; 1084 const char *generic = strchr(full_name, '<'); 1085 // if before the arguments list begins there is a template sign 1086 // then scan to the end of the generic args before you try to find 1087 // the arguments list 1088 if (generic && open_paren && generic < open_paren) { 1089 int generic_depth = 1; 1090 ++generic; 1091 for (; *generic && generic_depth > 0; generic++) { 1092 if (*generic == '<') 1093 generic_depth++; 1094 if (*generic == '>') 1095 generic_depth--; 1096 } 1097 if (*generic) 1098 open_paren = strchr(generic, '('); 1099 else 1100 open_paren = nullptr; 1101 } 1102 1103 if (open_paren) { 1104 if (IsToken(open_paren, "(anonymous namespace)")) { 1105 open_paren = strchr(open_paren + strlen("(anonymous namespace)"), '('); 1106 if (open_paren) 1107 close_paren = strchr(open_paren, ')'); 1108 } else 1109 close_paren = strchr(open_paren, ')'); 1110 } 1111 1112 return {open_paren, close_paren}; 1113 } 1114 1115 /// Writes out the function name in 'full_name' to 'out_stream' 1116 /// but replaces each argument type with the variable name 1117 /// and the corresponding pretty-printed value 1118 static void PrettyPrintFunctionNameWithArgs(Stream &out_stream, 1119 char const *full_name, 1120 ExecutionContextScope *exe_scope, 1121 VariableList const &args) { 1122 auto [open_paren, close_paren] = ParseBaseName(full_name); 1123 if (open_paren) 1124 out_stream.Write(full_name, open_paren - full_name + 1); 1125 else { 1126 out_stream.PutCString(full_name); 1127 out_stream.PutChar('('); 1128 } 1129 1130 FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope); 1131 1132 if (close_paren) 1133 out_stream.PutCString(close_paren); 1134 else 1135 out_stream.PutChar(')'); 1136 } 1137 1138 static void FormatInlinedBlock(Stream &out_stream, Block *block) { 1139 if (!block) 1140 return; 1141 Block *inline_block = block->GetContainingInlinedBlock(); 1142 if (inline_block) { 1143 if (const InlineFunctionInfo *inline_info = 1144 inline_block->GetInlinedFunctionInfo()) { 1145 out_stream.PutCString(" [inlined] "); 1146 inline_info->GetName().Dump(&out_stream); 1147 } 1148 } 1149 } 1150 1151 bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s, 1152 const SymbolContext *sc, 1153 const ExecutionContext *exe_ctx, 1154 const Address *addr, ValueObject *valobj, 1155 bool function_changed, 1156 bool initial_function) { 1157 if (!format_str.empty()) { 1158 FormatEntity::Entry root; 1159 Status error = FormatEntity::Parse(format_str, root); 1160 if (error.Success()) { 1161 return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj, 1162 function_changed, initial_function); 1163 } 1164 } 1165 return false; 1166 } 1167 1168 bool FormatEntity::FormatCString(const char *format, Stream &s, 1169 const SymbolContext *sc, 1170 const ExecutionContext *exe_ctx, 1171 const Address *addr, ValueObject *valobj, 1172 bool function_changed, bool initial_function) { 1173 if (format && format[0]) { 1174 FormatEntity::Entry root; 1175 llvm::StringRef format_str(format); 1176 Status error = FormatEntity::Parse(format_str, root); 1177 if (error.Success()) { 1178 return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj, 1179 function_changed, initial_function); 1180 } 1181 } 1182 return false; 1183 } 1184 1185 bool FormatEntity::Format(const Entry &entry, Stream &s, 1186 const SymbolContext *sc, 1187 const ExecutionContext *exe_ctx, const Address *addr, 1188 ValueObject *valobj, bool function_changed, 1189 bool initial_function) { 1190 switch (entry.type) { 1191 case Entry::Type::Invalid: 1192 case Entry::Type::ParentNumber: // Only used for 1193 // FormatEntity::Entry::Definition encoding 1194 case Entry::Type::ParentString: // Only used for 1195 // FormatEntity::Entry::Definition encoding 1196 return false; 1197 case Entry::Type::EscapeCode: 1198 if (exe_ctx) { 1199 if (Target *target = exe_ctx->GetTargetPtr()) { 1200 Debugger &debugger = target->GetDebugger(); 1201 if (debugger.GetUseColor()) { 1202 s.PutCString(entry.string); 1203 } 1204 } 1205 } 1206 // Always return true, so colors being disabled is transparent. 1207 return true; 1208 1209 case Entry::Type::Root: 1210 for (const auto &child : entry.children) { 1211 if (!Format(child, s, sc, exe_ctx, addr, valobj, function_changed, 1212 initial_function)) { 1213 return false; // If any item of root fails, then the formatting fails 1214 } 1215 } 1216 return true; // Only return true if all items succeeded 1217 1218 case Entry::Type::String: 1219 s.PutCString(entry.string); 1220 return true; 1221 1222 case Entry::Type::Scope: { 1223 StreamString scope_stream; 1224 bool success = false; 1225 for (const auto &child : entry.children) { 1226 success = Format(child, scope_stream, sc, exe_ctx, addr, valobj, 1227 function_changed, initial_function); 1228 if (!success) 1229 break; 1230 } 1231 // Only if all items in a scope succeed, then do we print the output into 1232 // the main stream 1233 if (success) 1234 s.Write(scope_stream.GetString().data(), scope_stream.GetString().size()); 1235 } 1236 return true; // Scopes always successfully print themselves 1237 1238 case Entry::Type::Variable: 1239 case Entry::Type::VariableSynthetic: 1240 case Entry::Type::ScriptVariable: 1241 case Entry::Type::ScriptVariableSynthetic: 1242 return DumpValue(s, sc, exe_ctx, entry, valobj); 1243 1244 case Entry::Type::AddressFile: 1245 case Entry::Type::AddressLoad: 1246 case Entry::Type::AddressLoadOrFile: 1247 return ( 1248 addr != nullptr && addr->IsValid() && 1249 DumpAddressAndContent(s, sc, exe_ctx, *addr, 1250 entry.type == Entry::Type::AddressLoadOrFile)); 1251 1252 case Entry::Type::ProcessID: 1253 if (exe_ctx) { 1254 Process *process = exe_ctx->GetProcessPtr(); 1255 if (process) { 1256 const char *format = "%" PRIu64; 1257 if (!entry.printf_format.empty()) 1258 format = entry.printf_format.c_str(); 1259 s.Printf(format, process->GetID()); 1260 return true; 1261 } 1262 } 1263 return false; 1264 1265 case Entry::Type::ProcessFile: 1266 if (exe_ctx) { 1267 Process *process = exe_ctx->GetProcessPtr(); 1268 if (process) { 1269 Module *exe_module = process->GetTarget().GetExecutableModulePointer(); 1270 if (exe_module) { 1271 if (DumpFile(s, exe_module->GetFileSpec(), (FileKind)entry.number)) 1272 return true; 1273 } 1274 } 1275 } 1276 return false; 1277 1278 case Entry::Type::ScriptProcess: 1279 if (exe_ctx) { 1280 Process *process = exe_ctx->GetProcessPtr(); 1281 if (process) 1282 return RunScriptFormatKeyword(s, sc, exe_ctx, process, 1283 entry.string.c_str()); 1284 } 1285 return false; 1286 1287 case Entry::Type::ThreadID: 1288 if (exe_ctx) { 1289 Thread *thread = exe_ctx->GetThreadPtr(); 1290 if (thread) { 1291 const char *format = "0x%4.4" PRIx64; 1292 if (!entry.printf_format.empty()) { 1293 // Watch for the special "tid" format... 1294 if (entry.printf_format == "tid") { 1295 // TODO(zturner): Rather than hardcoding this to be platform 1296 // specific, it should be controlled by a setting and the default 1297 // value of the setting can be different depending on the platform. 1298 Target &target = thread->GetProcess()->GetTarget(); 1299 ArchSpec arch(target.GetArchitecture()); 1300 llvm::Triple::OSType ostype = arch.IsValid() 1301 ? arch.GetTriple().getOS() 1302 : llvm::Triple::UnknownOS; 1303 if (ostype == llvm::Triple::FreeBSD || 1304 ostype == llvm::Triple::Linux || 1305 ostype == llvm::Triple::NetBSD || 1306 ostype == llvm::Triple::OpenBSD) { 1307 format = "%" PRIu64; 1308 } 1309 } else { 1310 format = entry.printf_format.c_str(); 1311 } 1312 } 1313 s.Printf(format, thread->GetID()); 1314 return true; 1315 } 1316 } 1317 return false; 1318 1319 case Entry::Type::ThreadProtocolID: 1320 if (exe_ctx) { 1321 Thread *thread = exe_ctx->GetThreadPtr(); 1322 if (thread) { 1323 const char *format = "0x%4.4" PRIx64; 1324 if (!entry.printf_format.empty()) 1325 format = entry.printf_format.c_str(); 1326 s.Printf(format, thread->GetProtocolID()); 1327 return true; 1328 } 1329 } 1330 return false; 1331 1332 case Entry::Type::ThreadIndexID: 1333 if (exe_ctx) { 1334 Thread *thread = exe_ctx->GetThreadPtr(); 1335 if (thread) { 1336 const char *format = "%" PRIu32; 1337 if (!entry.printf_format.empty()) 1338 format = entry.printf_format.c_str(); 1339 s.Printf(format, thread->GetIndexID()); 1340 return true; 1341 } 1342 } 1343 return false; 1344 1345 case Entry::Type::ThreadName: 1346 if (exe_ctx) { 1347 Thread *thread = exe_ctx->GetThreadPtr(); 1348 if (thread) { 1349 const char *cstr = thread->GetName(); 1350 if (cstr && cstr[0]) { 1351 s.PutCString(cstr); 1352 return true; 1353 } 1354 } 1355 } 1356 return false; 1357 1358 case Entry::Type::ThreadQueue: 1359 if (exe_ctx) { 1360 Thread *thread = exe_ctx->GetThreadPtr(); 1361 if (thread) { 1362 const char *cstr = thread->GetQueueName(); 1363 if (cstr && cstr[0]) { 1364 s.PutCString(cstr); 1365 return true; 1366 } 1367 } 1368 } 1369 return false; 1370 1371 case Entry::Type::ThreadStopReason: 1372 if (exe_ctx) { 1373 if (Thread *thread = exe_ctx->GetThreadPtr()) { 1374 std::string stop_description = thread->GetStopDescription(); 1375 if (!stop_description.empty()) { 1376 s.PutCString(stop_description); 1377 return true; 1378 } 1379 } 1380 } 1381 return false; 1382 1383 case Entry::Type::ThreadStopReasonRaw: 1384 if (exe_ctx) { 1385 if (Thread *thread = exe_ctx->GetThreadPtr()) { 1386 std::string stop_description = thread->GetStopDescriptionRaw(); 1387 if (!stop_description.empty()) { 1388 s.PutCString(stop_description); 1389 return true; 1390 } 1391 } 1392 } 1393 return false; 1394 1395 case Entry::Type::ThreadReturnValue: 1396 if (exe_ctx) { 1397 Thread *thread = exe_ctx->GetThreadPtr(); 1398 if (thread) { 1399 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1400 if (stop_info_sp && stop_info_sp->IsValid()) { 1401 ValueObjectSP return_valobj_sp = 1402 StopInfo::GetReturnValueObject(stop_info_sp); 1403 if (return_valobj_sp) { 1404 if (llvm::Error error = return_valobj_sp->Dump(s)) { 1405 s << "error: " << toString(std::move(error)); 1406 return false; 1407 } 1408 return true; 1409 } 1410 } 1411 } 1412 } 1413 return false; 1414 1415 case Entry::Type::ThreadCompletedExpression: 1416 if (exe_ctx) { 1417 Thread *thread = exe_ctx->GetThreadPtr(); 1418 if (thread) { 1419 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1420 if (stop_info_sp && stop_info_sp->IsValid()) { 1421 ExpressionVariableSP expression_var_sp = 1422 StopInfo::GetExpressionVariable(stop_info_sp); 1423 if (expression_var_sp && expression_var_sp->GetValueObject()) { 1424 if (llvm::Error error = 1425 expression_var_sp->GetValueObject()->Dump(s)) { 1426 s << "error: " << toString(std::move(error)); 1427 return false; 1428 } 1429 return true; 1430 } 1431 } 1432 } 1433 } 1434 return false; 1435 1436 case Entry::Type::ScriptThread: 1437 if (exe_ctx) { 1438 Thread *thread = exe_ctx->GetThreadPtr(); 1439 if (thread) 1440 return RunScriptFormatKeyword(s, sc, exe_ctx, thread, 1441 entry.string.c_str()); 1442 } 1443 return false; 1444 1445 case Entry::Type::ThreadInfo: 1446 if (exe_ctx) { 1447 Thread *thread = exe_ctx->GetThreadPtr(); 1448 if (thread) { 1449 StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); 1450 if (object_sp && 1451 object_sp->GetType() == eStructuredDataTypeDictionary) { 1452 if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s)) 1453 return true; 1454 } 1455 } 1456 } 1457 return false; 1458 1459 case Entry::Type::TargetArch: 1460 if (exe_ctx) { 1461 Target *target = exe_ctx->GetTargetPtr(); 1462 if (target) { 1463 const ArchSpec &arch = target->GetArchitecture(); 1464 if (arch.IsValid()) { 1465 s.PutCString(arch.GetArchitectureName()); 1466 return true; 1467 } 1468 } 1469 } 1470 return false; 1471 1472 case Entry::Type::ScriptTarget: 1473 if (exe_ctx) { 1474 Target *target = exe_ctx->GetTargetPtr(); 1475 if (target) 1476 return RunScriptFormatKeyword(s, sc, exe_ctx, target, 1477 entry.string.c_str()); 1478 } 1479 return false; 1480 1481 case Entry::Type::ModuleFile: 1482 if (sc) { 1483 Module *module = sc->module_sp.get(); 1484 if (module) { 1485 if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number)) 1486 return true; 1487 } 1488 } 1489 return false; 1490 1491 case Entry::Type::File: 1492 if (sc) { 1493 CompileUnit *cu = sc->comp_unit; 1494 if (cu) { 1495 if (DumpFile(s, cu->GetPrimaryFile(), (FileKind)entry.number)) 1496 return true; 1497 } 1498 } 1499 return false; 1500 1501 case Entry::Type::Lang: 1502 if (sc) { 1503 CompileUnit *cu = sc->comp_unit; 1504 if (cu) { 1505 const char *lang_name = 1506 Language::GetNameForLanguageType(cu->GetLanguage()); 1507 if (lang_name) { 1508 s.PutCString(lang_name); 1509 return true; 1510 } 1511 } 1512 } 1513 return false; 1514 1515 case Entry::Type::FrameIndex: 1516 if (exe_ctx) { 1517 StackFrame *frame = exe_ctx->GetFramePtr(); 1518 if (frame) { 1519 const char *format = "%" PRIu32; 1520 if (!entry.printf_format.empty()) 1521 format = entry.printf_format.c_str(); 1522 s.Printf(format, frame->GetFrameIndex()); 1523 return true; 1524 } 1525 } 1526 return false; 1527 1528 case Entry::Type::FrameRegisterPC: 1529 if (exe_ctx) { 1530 StackFrame *frame = exe_ctx->GetFramePtr(); 1531 if (frame) { 1532 const Address &pc_addr = frame->GetFrameCodeAddress(); 1533 if (pc_addr.IsValid()) { 1534 if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false)) 1535 return true; 1536 } 1537 } 1538 } 1539 return false; 1540 1541 case Entry::Type::FrameRegisterSP: 1542 if (exe_ctx) { 1543 StackFrame *frame = exe_ctx->GetFramePtr(); 1544 if (frame) { 1545 if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 1546 (lldb::Format)entry.number)) 1547 return true; 1548 } 1549 } 1550 return false; 1551 1552 case Entry::Type::FrameRegisterFP: 1553 if (exe_ctx) { 1554 StackFrame *frame = exe_ctx->GetFramePtr(); 1555 if (frame) { 1556 if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, 1557 (lldb::Format)entry.number)) 1558 return true; 1559 } 1560 } 1561 return false; 1562 1563 case Entry::Type::FrameRegisterFlags: 1564 if (exe_ctx) { 1565 StackFrame *frame = exe_ctx->GetFramePtr(); 1566 if (frame) { 1567 if (DumpRegister(s, frame, eRegisterKindGeneric, 1568 LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number)) 1569 return true; 1570 } 1571 } 1572 return false; 1573 1574 case Entry::Type::FrameNoDebug: 1575 if (exe_ctx) { 1576 StackFrame *frame = exe_ctx->GetFramePtr(); 1577 if (frame) { 1578 return !frame->HasDebugInformation(); 1579 } 1580 } 1581 return true; 1582 1583 case Entry::Type::FrameRegisterByName: 1584 if (exe_ctx) { 1585 StackFrame *frame = exe_ctx->GetFramePtr(); 1586 if (frame) { 1587 if (DumpRegister(s, frame, entry.string.c_str(), 1588 (lldb::Format)entry.number)) 1589 return true; 1590 } 1591 } 1592 return false; 1593 1594 case Entry::Type::FrameIsArtificial: { 1595 if (exe_ctx) 1596 if (StackFrame *frame = exe_ctx->GetFramePtr()) 1597 return frame->IsArtificial(); 1598 return false; 1599 } 1600 1601 case Entry::Type::ScriptFrame: 1602 if (exe_ctx) { 1603 StackFrame *frame = exe_ctx->GetFramePtr(); 1604 if (frame) 1605 return RunScriptFormatKeyword(s, sc, exe_ctx, frame, 1606 entry.string.c_str()); 1607 } 1608 return false; 1609 1610 case Entry::Type::FunctionID: 1611 if (sc) { 1612 if (sc->function) { 1613 s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); 1614 return true; 1615 } else if (sc->symbol) { 1616 s.Printf("symbol[%u]", sc->symbol->GetID()); 1617 return true; 1618 } 1619 } 1620 return false; 1621 1622 case Entry::Type::FunctionDidChange: 1623 return function_changed; 1624 1625 case Entry::Type::FunctionInitialFunction: 1626 return initial_function; 1627 1628 case Entry::Type::FunctionName: { 1629 if (!sc) 1630 return false; 1631 1632 Language *language_plugin = nullptr; 1633 bool language_plugin_handled = false; 1634 StreamString ss; 1635 1636 if (sc->function) 1637 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1638 else if (sc->symbol) 1639 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1640 1641 if (language_plugin) 1642 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1643 sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss); 1644 1645 if (language_plugin_handled) { 1646 s << ss.GetString(); 1647 return true; 1648 } else { 1649 const char *name = nullptr; 1650 if (sc->function) 1651 name = sc->function->GetName().AsCString(nullptr); 1652 else if (sc->symbol) 1653 name = sc->symbol->GetName().AsCString(nullptr); 1654 1655 if (name) { 1656 s.PutCString(name); 1657 FormatInlinedBlock(s, sc->block); 1658 return true; 1659 } 1660 } 1661 } 1662 return false; 1663 1664 case Entry::Type::FunctionNameNoArgs: { 1665 if (!sc) 1666 return false; 1667 1668 Language *language_plugin = nullptr; 1669 bool language_plugin_handled = false; 1670 StreamString ss; 1671 if (sc->function) 1672 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1673 else if (sc->symbol) 1674 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1675 1676 if (language_plugin) 1677 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1678 sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs, 1679 ss); 1680 1681 if (language_plugin_handled) { 1682 s << ss.GetString(); 1683 return true; 1684 } else { 1685 ConstString name; 1686 if (sc->function) 1687 name = sc->function->GetNameNoArguments(); 1688 else if (sc->symbol) 1689 name = sc->symbol->GetNameNoArguments(); 1690 if (name) { 1691 s.PutCString(name.GetCString()); 1692 FormatInlinedBlock(s, sc->block); 1693 return true; 1694 } 1695 } 1696 } 1697 return false; 1698 1699 case Entry::Type::FunctionNameWithArgs: { 1700 if (!sc) 1701 return false; 1702 1703 Language *language_plugin = nullptr; 1704 bool language_plugin_handled = false; 1705 StreamString ss; 1706 if (sc->function) 1707 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1708 else if (sc->symbol) 1709 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1710 1711 if (language_plugin) 1712 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1713 sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss); 1714 1715 if (language_plugin_handled) { 1716 s << ss.GetString(); 1717 return true; 1718 } else { 1719 // Print the function name with arguments in it 1720 if (sc->function) { 1721 ExecutionContextScope *exe_scope = 1722 exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; 1723 const char *cstr = sc->function->GetName().AsCString(nullptr); 1724 if (cstr) { 1725 const InlineFunctionInfo *inline_info = nullptr; 1726 VariableListSP variable_list_sp; 1727 bool get_function_vars = true; 1728 if (sc->block) { 1729 Block *inline_block = sc->block->GetContainingInlinedBlock(); 1730 1731 if (inline_block) { 1732 get_function_vars = false; 1733 inline_info = inline_block->GetInlinedFunctionInfo(); 1734 if (inline_info) 1735 variable_list_sp = inline_block->GetBlockVariableList(true); 1736 } 1737 } 1738 1739 if (get_function_vars) { 1740 variable_list_sp = 1741 sc->function->GetBlock(true).GetBlockVariableList(true); 1742 } 1743 1744 if (inline_info) { 1745 s.PutCString(cstr); 1746 s.PutCString(" [inlined] "); 1747 cstr = inline_info->GetName().GetCString(); 1748 } 1749 1750 VariableList args; 1751 if (variable_list_sp) 1752 variable_list_sp->AppendVariablesWithScope( 1753 eValueTypeVariableArgument, args); 1754 if (args.GetSize() > 0) { 1755 PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args); 1756 } else { 1757 s.PutCString(cstr); 1758 } 1759 return true; 1760 } 1761 } else if (sc->symbol) { 1762 const char *cstr = sc->symbol->GetName().AsCString(nullptr); 1763 if (cstr) { 1764 s.PutCString(cstr); 1765 return true; 1766 } 1767 } 1768 } 1769 } 1770 return false; 1771 1772 case Entry::Type::FunctionMangledName: { 1773 if (!sc) 1774 return false; 1775 1776 const char *name = nullptr; 1777 if (sc->symbol) 1778 name = 1779 sc->symbol->GetMangled().GetName(Mangled::ePreferMangled).AsCString(); 1780 else if (sc->function) 1781 name = sc->function->GetMangled() 1782 .GetName(Mangled::ePreferMangled) 1783 .AsCString(); 1784 1785 if (!name) 1786 return false; 1787 s.PutCString(name); 1788 FormatInlinedBlock(s, sc->block); 1789 return true; 1790 } 1791 case Entry::Type::FunctionAddrOffset: 1792 if (addr) { 1793 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false, 1794 false)) 1795 return true; 1796 } 1797 return false; 1798 1799 case Entry::Type::FunctionAddrOffsetConcrete: 1800 if (addr) { 1801 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, true, true, 1802 true)) 1803 return true; 1804 } 1805 return false; 1806 1807 case Entry::Type::FunctionLineOffset: 1808 if (sc) 1809 return (DumpAddressOffsetFromFunction( 1810 s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false, 1811 false)); 1812 return false; 1813 1814 case Entry::Type::FunctionPCOffset: 1815 if (exe_ctx) { 1816 StackFrame *frame = exe_ctx->GetFramePtr(); 1817 if (frame) { 1818 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, 1819 frame->GetFrameCodeAddress(), false, 1820 false, false)) 1821 return true; 1822 } 1823 } 1824 return false; 1825 1826 case Entry::Type::FunctionChanged: 1827 return function_changed; 1828 1829 case Entry::Type::FunctionIsOptimized: { 1830 bool is_optimized = false; 1831 if (sc && sc->function && sc->function->GetIsOptimized()) { 1832 is_optimized = true; 1833 } 1834 return is_optimized; 1835 } 1836 1837 case Entry::Type::FunctionInitial: 1838 return initial_function; 1839 1840 case Entry::Type::LineEntryFile: 1841 if (sc && sc->line_entry.IsValid()) { 1842 Module *module = sc->module_sp.get(); 1843 if (module) { 1844 if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number)) 1845 return true; 1846 } 1847 } 1848 return false; 1849 1850 case Entry::Type::LineEntryLineNumber: 1851 if (sc && sc->line_entry.IsValid()) { 1852 const char *format = "%" PRIu32; 1853 if (!entry.printf_format.empty()) 1854 format = entry.printf_format.c_str(); 1855 s.Printf(format, sc->line_entry.line); 1856 return true; 1857 } 1858 return false; 1859 1860 case Entry::Type::LineEntryColumn: 1861 if (sc && sc->line_entry.IsValid() && sc->line_entry.column) { 1862 const char *format = "%" PRIu32; 1863 if (!entry.printf_format.empty()) 1864 format = entry.printf_format.c_str(); 1865 s.Printf(format, sc->line_entry.column); 1866 return true; 1867 } 1868 return false; 1869 1870 case Entry::Type::LineEntryStartAddress: 1871 case Entry::Type::LineEntryEndAddress: 1872 if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) { 1873 Address addr = sc->line_entry.range.GetBaseAddress(); 1874 1875 if (entry.type == Entry::Type::LineEntryEndAddress) 1876 addr.Slide(sc->line_entry.range.GetByteSize()); 1877 if (DumpAddressAndContent(s, sc, exe_ctx, addr, false)) 1878 return true; 1879 } 1880 return false; 1881 1882 case Entry::Type::CurrentPCArrow: 1883 if (addr && exe_ctx && exe_ctx->GetFramePtr()) { 1884 RegisterContextSP reg_ctx = 1885 exe_ctx->GetFramePtr()->GetRegisterContextSP(); 1886 if (reg_ctx) { 1887 addr_t pc_loadaddr = reg_ctx->GetPC(); 1888 if (pc_loadaddr != LLDB_INVALID_ADDRESS) { 1889 Address pc; 1890 pc.SetLoadAddress(pc_loadaddr, exe_ctx->GetTargetPtr()); 1891 if (pc == *addr) { 1892 s.Printf("-> "); 1893 return true; 1894 } 1895 } 1896 } 1897 s.Printf(" "); 1898 return true; 1899 } 1900 return false; 1901 } 1902 return false; 1903 } 1904 1905 static bool DumpCommaSeparatedChildEntryNames(Stream &s, 1906 const Definition *parent) { 1907 if (parent->children) { 1908 const size_t n = parent->num_children; 1909 for (size_t i = 0; i < n; ++i) { 1910 if (i > 0) 1911 s.PutCString(", "); 1912 s.Printf("\"%s\"", parent->children[i].name); 1913 } 1914 return true; 1915 } 1916 return false; 1917 } 1918 1919 static Status ParseEntry(const llvm::StringRef &format_str, 1920 const Definition *parent, FormatEntity::Entry &entry) { 1921 Status error; 1922 1923 const size_t sep_pos = format_str.find_first_of(".[:"); 1924 const char sep_char = 1925 (sep_pos == llvm::StringRef::npos) ? '\0' : format_str[sep_pos]; 1926 llvm::StringRef key = format_str.substr(0, sep_pos); 1927 1928 const size_t n = parent->num_children; 1929 for (size_t i = 0; i < n; ++i) { 1930 const Definition *entry_def = parent->children + i; 1931 if (key == entry_def->name || entry_def->name[0] == '*') { 1932 llvm::StringRef value; 1933 if (sep_char) 1934 value = 1935 format_str.substr(sep_pos + (entry_def->keep_separator ? 0 : 1)); 1936 switch (entry_def->type) { 1937 case FormatEntity::Entry::Type::ParentString: 1938 entry.string = format_str.str(); 1939 return error; // Success 1940 1941 case FormatEntity::Entry::Type::ParentNumber: 1942 entry.number = entry_def->data; 1943 return error; // Success 1944 1945 case FormatEntity::Entry::Type::EscapeCode: 1946 entry.type = entry_def->type; 1947 entry.string = entry_def->string; 1948 return error; // Success 1949 1950 default: 1951 entry.type = entry_def->type; 1952 break; 1953 } 1954 1955 if (value.empty()) { 1956 if (entry_def->type == FormatEntity::Entry::Type::Invalid) { 1957 if (entry_def->children) { 1958 StreamString error_strm; 1959 error_strm.Printf("'%s' can't be specified on its own, you must " 1960 "access one of its children: ", 1961 entry_def->name); 1962 DumpCommaSeparatedChildEntryNames(error_strm, entry_def); 1963 error.SetErrorStringWithFormat("%s", error_strm.GetData()); 1964 } else if (sep_char == ':') { 1965 // Any value whose separator is a with a ':' means this value has a 1966 // string argument that needs to be stored in the entry (like 1967 // "${script.var:}"). In this case the string value is the empty 1968 // string which is ok. 1969 } else { 1970 error.SetErrorStringWithFormat("%s", "invalid entry definitions"); 1971 } 1972 } 1973 } else { 1974 if (entry_def->children) { 1975 error = ParseEntry(value, entry_def, entry); 1976 } else if (sep_char == ':') { 1977 // Any value whose separator is a with a ':' means this value has a 1978 // string argument that needs to be stored in the entry (like 1979 // "${script.var:modulename.function}") 1980 entry.string = value.str(); 1981 } else { 1982 error.SetErrorStringWithFormat( 1983 "'%s' followed by '%s' but it has no children", key.str().c_str(), 1984 value.str().c_str()); 1985 } 1986 } 1987 return error; 1988 } 1989 } 1990 StreamString error_strm; 1991 if (parent->type == FormatEntity::Entry::Type::Root) 1992 error_strm.Printf( 1993 "invalid top level item '%s'. Valid top level items are: ", 1994 key.str().c_str()); 1995 else 1996 error_strm.Printf("invalid member '%s' in '%s'. Valid members are: ", 1997 key.str().c_str(), parent->name); 1998 DumpCommaSeparatedChildEntryNames(error_strm, parent); 1999 error.SetErrorStringWithFormat("%s", error_strm.GetData()); 2000 return error; 2001 } 2002 2003 static const Definition *FindEntry(const llvm::StringRef &format_str, 2004 const Definition *parent, 2005 llvm::StringRef &remainder) { 2006 Status error; 2007 2008 std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.'); 2009 const size_t n = parent->num_children; 2010 for (size_t i = 0; i < n; ++i) { 2011 const Definition *entry_def = parent->children + i; 2012 if (p.first == entry_def->name || entry_def->name[0] == '*') { 2013 if (p.second.empty()) { 2014 if (format_str.back() == '.') 2015 remainder = format_str.drop_front(format_str.size() - 1); 2016 else 2017 remainder = llvm::StringRef(); // Exact match 2018 return entry_def; 2019 } else { 2020 if (entry_def->children) { 2021 return FindEntry(p.second, entry_def, remainder); 2022 } else { 2023 remainder = p.second; 2024 return entry_def; 2025 } 2026 } 2027 } 2028 } 2029 remainder = format_str; 2030 return parent; 2031 } 2032 2033 static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, 2034 uint32_t depth) { 2035 Status error; 2036 while (!format.empty() && error.Success()) { 2037 const size_t non_special_chars = format.find_first_of("${}\\"); 2038 2039 if (non_special_chars == llvm::StringRef::npos) { 2040 // No special characters, just string bytes so add them and we are done 2041 parent_entry.AppendText(format); 2042 return error; 2043 } 2044 2045 if (non_special_chars > 0) { 2046 // We have a special character, so add all characters before these as a 2047 // plain string 2048 parent_entry.AppendText(format.substr(0, non_special_chars)); 2049 format = format.drop_front(non_special_chars); 2050 } 2051 2052 switch (format[0]) { 2053 case '\0': 2054 return error; 2055 2056 case '{': { 2057 format = format.drop_front(); // Skip the '{' 2058 Entry scope_entry(Entry::Type::Scope); 2059 error = ParseInternal(format, scope_entry, depth + 1); 2060 if (error.Fail()) 2061 return error; 2062 parent_entry.AppendEntry(std::move(scope_entry)); 2063 } break; 2064 2065 case '}': 2066 if (depth == 0) 2067 error.SetErrorString("unmatched '}' character"); 2068 else 2069 format = 2070 format 2071 .drop_front(); // Skip the '}' as we are at the end of the scope 2072 return error; 2073 2074 case '\\': { 2075 format = format.drop_front(); // Skip the '\' character 2076 if (format.empty()) { 2077 error.SetErrorString( 2078 "'\\' character was not followed by another character"); 2079 return error; 2080 } 2081 2082 const char desens_char = format[0]; 2083 format = format.drop_front(); // Skip the desensitized char character 2084 switch (desens_char) { 2085 case 'a': 2086 parent_entry.AppendChar('\a'); 2087 break; 2088 case 'b': 2089 parent_entry.AppendChar('\b'); 2090 break; 2091 case 'f': 2092 parent_entry.AppendChar('\f'); 2093 break; 2094 case 'n': 2095 parent_entry.AppendChar('\n'); 2096 break; 2097 case 'r': 2098 parent_entry.AppendChar('\r'); 2099 break; 2100 case 't': 2101 parent_entry.AppendChar('\t'); 2102 break; 2103 case 'v': 2104 parent_entry.AppendChar('\v'); 2105 break; 2106 case '\'': 2107 parent_entry.AppendChar('\''); 2108 break; 2109 case '\\': 2110 parent_entry.AppendChar('\\'); 2111 break; 2112 case '0': 2113 // 1 to 3 octal chars 2114 { 2115 // Make a string that can hold onto the initial zero char, up to 3 2116 // octal digits, and a terminating NULL. 2117 char oct_str[5] = {0, 0, 0, 0, 0}; 2118 2119 int i; 2120 for (i = 0; (format[i] >= '0' && format[i] <= '7') && i < 4; ++i) 2121 oct_str[i] = format[i]; 2122 2123 // We don't want to consume the last octal character since the main 2124 // for loop will do this for us, so we advance p by one less than i 2125 // (even if i is zero) 2126 format = format.drop_front(i); 2127 unsigned long octal_value = ::strtoul(oct_str, nullptr, 8); 2128 if (octal_value <= UINT8_MAX) { 2129 parent_entry.AppendChar((char)octal_value); 2130 } else { 2131 error.SetErrorString("octal number is larger than a single byte"); 2132 return error; 2133 } 2134 } 2135 break; 2136 2137 case 'x': 2138 // hex number in the format 2139 if (isxdigit(format[0])) { 2140 // Make a string that can hold onto two hex chars plus a 2141 // NULL terminator 2142 char hex_str[3] = {0, 0, 0}; 2143 hex_str[0] = format[0]; 2144 2145 format = format.drop_front(); 2146 2147 if (isxdigit(format[0])) { 2148 hex_str[1] = format[0]; 2149 format = format.drop_front(); 2150 } 2151 2152 unsigned long hex_value = strtoul(hex_str, nullptr, 16); 2153 if (hex_value <= UINT8_MAX) { 2154 parent_entry.AppendChar((char)hex_value); 2155 } else { 2156 error.SetErrorString("hex number is larger than a single byte"); 2157 return error; 2158 } 2159 } else { 2160 parent_entry.AppendChar(desens_char); 2161 } 2162 break; 2163 2164 default: 2165 // Just desensitize any other character by just printing what came 2166 // after the '\' 2167 parent_entry.AppendChar(desens_char); 2168 break; 2169 } 2170 } break; 2171 2172 case '$': 2173 format = format.drop_front(); // Skip the '$' 2174 if (format.empty() || format.front() != '{') { 2175 // Print '$' when not followed by '{'. 2176 parent_entry.AppendText("$"); 2177 } else { 2178 format = format.drop_front(); // Skip the '{' 2179 2180 llvm::StringRef variable, variable_format; 2181 error = FormatEntity::ExtractVariableInfo(format, variable, 2182 variable_format); 2183 if (error.Fail()) 2184 return error; 2185 bool verify_is_thread_id = false; 2186 Entry entry; 2187 if (!variable_format.empty()) { 2188 entry.printf_format = variable_format.str(); 2189 2190 // If the format contains a '%' we are going to assume this is a 2191 // printf style format. So if you want to format your thread ID 2192 // using "0x%llx" you can use: ${thread.id%0x%llx} 2193 // 2194 // If there is no '%' in the format, then it is assumed to be a 2195 // LLDB format name, or one of the extended formats specified in 2196 // the switch statement below. 2197 2198 if (entry.printf_format.find('%') == std::string::npos) { 2199 bool clear_printf = false; 2200 2201 if (entry.printf_format.size() == 1) { 2202 switch (entry.printf_format[0]) { 2203 case '@': // if this is an @ sign, print ObjC description 2204 entry.number = ValueObject:: 2205 eValueObjectRepresentationStyleLanguageSpecific; 2206 clear_printf = true; 2207 break; 2208 case 'V': // if this is a V, print the value using the default 2209 // format 2210 entry.number = 2211 ValueObject::eValueObjectRepresentationStyleValue; 2212 clear_printf = true; 2213 break; 2214 case 'L': // if this is an L, print the location of the value 2215 entry.number = 2216 ValueObject::eValueObjectRepresentationStyleLocation; 2217 clear_printf = true; 2218 break; 2219 case 'S': // if this is an S, print the summary after all 2220 entry.number = 2221 ValueObject::eValueObjectRepresentationStyleSummary; 2222 clear_printf = true; 2223 break; 2224 case '#': // if this is a '#', print the number of children 2225 entry.number = 2226 ValueObject::eValueObjectRepresentationStyleChildrenCount; 2227 clear_printf = true; 2228 break; 2229 case 'T': // if this is a 'T', print the type 2230 entry.number = ValueObject::eValueObjectRepresentationStyleType; 2231 clear_printf = true; 2232 break; 2233 case 'N': // if this is a 'N', print the name 2234 entry.number = ValueObject::eValueObjectRepresentationStyleName; 2235 clear_printf = true; 2236 break; 2237 case '>': // if this is a '>', print the expression path 2238 entry.number = 2239 ValueObject::eValueObjectRepresentationStyleExpressionPath; 2240 clear_printf = true; 2241 break; 2242 } 2243 } 2244 2245 if (entry.number == 0) { 2246 if (FormatManager::GetFormatFromCString( 2247 entry.printf_format.c_str(), entry.fmt)) { 2248 clear_printf = true; 2249 } else if (entry.printf_format == "tid") { 2250 verify_is_thread_id = true; 2251 } else { 2252 error.SetErrorStringWithFormat("invalid format: '%s'", 2253 entry.printf_format.c_str()); 2254 return error; 2255 } 2256 } 2257 2258 // Our format string turned out to not be a printf style format 2259 // so lets clear the string 2260 if (clear_printf) 2261 entry.printf_format.clear(); 2262 } 2263 } 2264 2265 // Check for dereferences 2266 if (variable[0] == '*') { 2267 entry.deref = true; 2268 variable = variable.drop_front(); 2269 } 2270 2271 error = ParseEntry(variable, &g_root, entry); 2272 if (error.Fail()) 2273 return error; 2274 2275 llvm::StringRef entry_string(entry.string); 2276 if (entry_string.contains(':')) { 2277 auto [_, llvm_format] = entry_string.split(':'); 2278 if (!llvm_format.empty() && !LLVMFormatPattern.match(llvm_format)) { 2279 error.SetErrorStringWithFormat("invalid llvm format: '%s'", 2280 llvm_format.data()); 2281 return error; 2282 } 2283 } 2284 2285 if (verify_is_thread_id) { 2286 if (entry.type != Entry::Type::ThreadID && 2287 entry.type != Entry::Type::ThreadProtocolID) { 2288 error.SetErrorString("the 'tid' format can only be used on " 2289 "${thread.id} and ${thread.protocol_id}"); 2290 } 2291 } 2292 2293 switch (entry.type) { 2294 case Entry::Type::Variable: 2295 case Entry::Type::VariableSynthetic: 2296 if (entry.number == 0) { 2297 if (entry.string.empty()) 2298 entry.number = ValueObject::eValueObjectRepresentationStyleValue; 2299 else 2300 entry.number = 2301 ValueObject::eValueObjectRepresentationStyleSummary; 2302 } 2303 break; 2304 default: 2305 // Make sure someone didn't try to dereference anything but ${var} 2306 // or ${svar} 2307 if (entry.deref) { 2308 error.SetErrorStringWithFormat( 2309 "${%s} can't be dereferenced, only ${var} and ${svar} can.", 2310 variable.str().c_str()); 2311 return error; 2312 } 2313 } 2314 parent_entry.AppendEntry(std::move(entry)); 2315 } 2316 break; 2317 } 2318 } 2319 return error; 2320 } 2321 2322 Status FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str, 2323 llvm::StringRef &variable_name, 2324 llvm::StringRef &variable_format) { 2325 Status error; 2326 variable_name = llvm::StringRef(); 2327 variable_format = llvm::StringRef(); 2328 2329 const size_t paren_pos = format_str.find('}'); 2330 if (paren_pos != llvm::StringRef::npos) { 2331 const size_t percent_pos = format_str.find('%'); 2332 if (percent_pos < paren_pos) { 2333 if (percent_pos > 0) { 2334 if (percent_pos > 1) 2335 variable_name = format_str.substr(0, percent_pos); 2336 variable_format = 2337 format_str.substr(percent_pos + 1, paren_pos - (percent_pos + 1)); 2338 } 2339 } else { 2340 variable_name = format_str.substr(0, paren_pos); 2341 } 2342 // Strip off elements and the formatting and the trailing '}' 2343 format_str = format_str.substr(paren_pos + 1); 2344 } else { 2345 error.SetErrorStringWithFormat( 2346 "missing terminating '}' character for '${%s'", 2347 format_str.str().c_str()); 2348 } 2349 return error; 2350 } 2351 2352 bool FormatEntity::FormatFileSpec(const FileSpec &file_spec, Stream &s, 2353 llvm::StringRef variable_name, 2354 llvm::StringRef variable_format) { 2355 if (variable_name.empty() || variable_name == ".fullpath") { 2356 file_spec.Dump(s.AsRawOstream()); 2357 return true; 2358 } else if (variable_name == ".basename") { 2359 s.PutCString(file_spec.GetFilename().GetStringRef()); 2360 return true; 2361 } else if (variable_name == ".dirname") { 2362 s.PutCString(file_spec.GetFilename().GetStringRef()); 2363 return true; 2364 } 2365 return false; 2366 } 2367 2368 static std::string MakeMatch(const llvm::StringRef &prefix, 2369 const char *suffix) { 2370 std::string match(prefix.str()); 2371 match.append(suffix); 2372 return match; 2373 } 2374 2375 static void AddMatches(const Definition *def, const llvm::StringRef &prefix, 2376 const llvm::StringRef &match_prefix, 2377 StringList &matches) { 2378 const size_t n = def->num_children; 2379 if (n > 0) { 2380 for (size_t i = 0; i < n; ++i) { 2381 std::string match = prefix.str(); 2382 if (match_prefix.empty()) 2383 matches.AppendString(MakeMatch(prefix, def->children[i].name)); 2384 else if (strncmp(def->children[i].name, match_prefix.data(), 2385 match_prefix.size()) == 0) 2386 matches.AppendString( 2387 MakeMatch(prefix, def->children[i].name + match_prefix.size())); 2388 } 2389 } 2390 } 2391 2392 void FormatEntity::AutoComplete(CompletionRequest &request) { 2393 llvm::StringRef str = request.GetCursorArgumentPrefix(); 2394 2395 const size_t dollar_pos = str.rfind('$'); 2396 if (dollar_pos == llvm::StringRef::npos) 2397 return; 2398 2399 // Hitting TAB after $ at the end of the string add a "{" 2400 if (dollar_pos == str.size() - 1) { 2401 std::string match = str.str(); 2402 match.append("{"); 2403 request.AddCompletion(match); 2404 return; 2405 } 2406 2407 if (str[dollar_pos + 1] != '{') 2408 return; 2409 2410 const size_t close_pos = str.find('}', dollar_pos + 2); 2411 if (close_pos != llvm::StringRef::npos) 2412 return; 2413 2414 const size_t format_pos = str.find('%', dollar_pos + 2); 2415 if (format_pos != llvm::StringRef::npos) 2416 return; 2417 2418 llvm::StringRef partial_variable(str.substr(dollar_pos + 2)); 2419 if (partial_variable.empty()) { 2420 // Suggest all top level entities as we are just past "${" 2421 StringList new_matches; 2422 AddMatches(&g_root, str, llvm::StringRef(), new_matches); 2423 request.AddCompletions(new_matches); 2424 return; 2425 } 2426 2427 // We have a partially specified variable, find it 2428 llvm::StringRef remainder; 2429 const Definition *entry_def = FindEntry(partial_variable, &g_root, remainder); 2430 if (!entry_def) 2431 return; 2432 2433 const size_t n = entry_def->num_children; 2434 2435 if (remainder.empty()) { 2436 // Exact match 2437 if (n > 0) { 2438 // "${thread.info" <TAB> 2439 request.AddCompletion(MakeMatch(str, ".")); 2440 } else { 2441 // "${thread.id" <TAB> 2442 request.AddCompletion(MakeMatch(str, "}")); 2443 } 2444 } else if (remainder == ".") { 2445 // "${thread." <TAB> 2446 StringList new_matches; 2447 AddMatches(entry_def, str, llvm::StringRef(), new_matches); 2448 request.AddCompletions(new_matches); 2449 } else { 2450 // We have a partial match 2451 // "${thre" <TAB> 2452 StringList new_matches; 2453 AddMatches(entry_def, str, remainder, new_matches); 2454 request.AddCompletions(new_matches); 2455 } 2456 } 2457 2458 void FormatEntity::PrettyPrintFunctionArguments( 2459 Stream &out_stream, VariableList const &args, 2460 ExecutionContextScope *exe_scope) { 2461 const size_t num_args = args.GetSize(); 2462 for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) { 2463 std::string buffer; 2464 2465 VariableSP var_sp(args.GetVariableAtIndex(arg_idx)); 2466 ValueObjectSP var_value_sp(ValueObjectVariable::Create(exe_scope, var_sp)); 2467 StreamString ss; 2468 llvm::StringRef var_representation; 2469 const char *var_name = var_value_sp->GetName().GetCString(); 2470 if (var_value_sp->GetCompilerType().IsValid()) { 2471 if (exe_scope && exe_scope->CalculateTarget()) 2472 var_value_sp = var_value_sp->GetQualifiedRepresentationIfAvailable( 2473 exe_scope->CalculateTarget() 2474 ->TargetProperties::GetPreferDynamicValue(), 2475 exe_scope->CalculateTarget() 2476 ->TargetProperties::GetEnableSyntheticValue()); 2477 if (var_value_sp->GetCompilerType().IsAggregateType() && 2478 DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) { 2479 static StringSummaryFormat format(TypeSummaryImpl::Flags() 2480 .SetHideItemNames(false) 2481 .SetShowMembersOneLiner(true), 2482 ""); 2483 format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); 2484 var_representation = buffer; 2485 } else 2486 var_value_sp->DumpPrintableRepresentation( 2487 ss, 2488 ValueObject::ValueObjectRepresentationStyle:: 2489 eValueObjectRepresentationStyleSummary, 2490 eFormatDefault, 2491 ValueObject::PrintableRepresentationSpecialCases::eAllow, false); 2492 } 2493 2494 if (!ss.GetString().empty()) 2495 var_representation = ss.GetString(); 2496 if (arg_idx > 0) 2497 out_stream.PutCString(", "); 2498 if (var_value_sp->GetError().Success()) { 2499 if (!var_representation.empty()) 2500 out_stream.Printf("%s=%s", var_name, var_representation.str().c_str()); 2501 else 2502 out_stream.Printf("%s=%s at %s", var_name, 2503 var_value_sp->GetTypeName().GetCString(), 2504 var_value_sp->GetLocationAsCString()); 2505 } else 2506 out_stream.Printf("%s=<unavailable>", var_name); 2507 } 2508 } 2509 2510 Status FormatEntity::Parse(const llvm::StringRef &format_str, Entry &entry) { 2511 entry.Clear(); 2512 entry.type = Entry::Type::Root; 2513 llvm::StringRef modifiable_format(format_str); 2514 return ParseInternal(modifiable_format, entry, 0); 2515 } 2516