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