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