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