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