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/ValueObject.h" 23 #include "lldb/Core/ValueObjectVariable.h" 24 #include "lldb/DataFormatters/DataVisualization.h" 25 #include "lldb/DataFormatters/FormatManager.h" 26 #include "lldb/DataFormatters/ValueObjectPrinter.h" 27 #include "lldb/Expression/ExpressionVariable.h" 28 #include "lldb/Interpreter/CommandInterpreter.h" 29 #include "lldb/Symbol/Block.h" 30 #include "lldb/Symbol/CompileUnit.h" 31 #include "lldb/Symbol/Function.h" 32 #include "lldb/Symbol/LineEntry.h" 33 #include "lldb/Symbol/Symbol.h" 34 #include "lldb/Symbol/VariableList.h" 35 #include "lldb/Target/ExecutionContext.h" 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/FileSpec.h" 46 #include "lldb/Utility/Stream.h" 47 #include "lldb/Utility/StreamString.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, \ 68 static_cast<uint32_t>(llvm::array_lengthof(c)), c, 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, \ 74 static_cast<uint32_t>(llvm::array_lengthof(c)), c, 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 ValueObject::GetValueForExpressionPathOptions options; 618 ValueObject::ExpressionPathEndResultType final_value_type; 619 ValueObject::ExpressionPathScanEndReason reason_to_stop; 620 ValueObject::ExpressionPathAftermath what_next = 621 (deref_pointer ? ValueObject::eExpressionPathAftermathDereference 622 : ValueObject::eExpressionPathAftermathNothing); 623 ValueObjectSP item = valobj->GetValueForExpressionPath( 624 ptr_deref_buffer.c_str(), &reason_to_stop, &final_value_type, options, 625 &what_next); 626 if (!item) { 627 if (log) 628 log->Printf("[ExpandIndexedExpression] ERROR: why stopping = %d," 629 " final_value_type %d", 630 reason_to_stop, final_value_type); 631 } else { 632 if (log) 633 log->Printf("[ExpandIndexedExpression] ALL RIGHT: why stopping = %d," 634 " final_value_type %d", 635 reason_to_stop, final_value_type); 636 } 637 return item; 638 } 639 640 static char ConvertValueObjectStyleToChar( 641 ValueObject::ValueObjectRepresentationStyle style) { 642 switch (style) { 643 case ValueObject::eValueObjectRepresentationStyleLanguageSpecific: 644 return '@'; 645 case ValueObject::eValueObjectRepresentationStyleValue: 646 return 'V'; 647 case ValueObject::eValueObjectRepresentationStyleLocation: 648 return 'L'; 649 case ValueObject::eValueObjectRepresentationStyleSummary: 650 return 'S'; 651 case ValueObject::eValueObjectRepresentationStyleChildrenCount: 652 return '#'; 653 case ValueObject::eValueObjectRepresentationStyleType: 654 return 'T'; 655 case ValueObject::eValueObjectRepresentationStyleName: 656 return 'N'; 657 case ValueObject::eValueObjectRepresentationStyleExpressionPath: 658 return '>'; 659 } 660 return '\0'; 661 } 662 663 static bool DumpValue(Stream &s, const SymbolContext *sc, 664 const ExecutionContext *exe_ctx, 665 const FormatEntity::Entry &entry, ValueObject *valobj) { 666 if (valobj == nullptr) 667 return false; 668 669 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS)); 670 Format custom_format = eFormatInvalid; 671 ValueObject::ValueObjectRepresentationStyle val_obj_display = 672 entry.string.empty() 673 ? ValueObject::eValueObjectRepresentationStyleValue 674 : ValueObject::eValueObjectRepresentationStyleSummary; 675 676 bool do_deref_pointer = entry.deref; 677 bool is_script = false; 678 switch (entry.type) { 679 case FormatEntity::Entry::Type::ScriptVariable: 680 is_script = true; 681 break; 682 683 case FormatEntity::Entry::Type::Variable: 684 custom_format = entry.fmt; 685 val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number; 686 break; 687 688 case FormatEntity::Entry::Type::ScriptVariableSynthetic: 689 is_script = true; 690 LLVM_FALLTHROUGH; 691 case FormatEntity::Entry::Type::VariableSynthetic: 692 custom_format = entry.fmt; 693 val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number; 694 if (!valobj->IsSynthetic()) { 695 valobj = valobj->GetSyntheticValue().get(); 696 if (valobj == nullptr) 697 return false; 698 } 699 break; 700 701 default: 702 return false; 703 } 704 705 if (valobj == nullptr) 706 return false; 707 708 ValueObject::ExpressionPathAftermath what_next = 709 (do_deref_pointer ? ValueObject::eExpressionPathAftermathDereference 710 : ValueObject::eExpressionPathAftermathNothing); 711 ValueObject::GetValueForExpressionPathOptions options; 712 options.DontCheckDotVsArrowSyntax() 713 .DoAllowBitfieldSyntax() 714 .DoAllowFragileIVar() 715 .SetSyntheticChildrenTraversal( 716 ValueObject::GetValueForExpressionPathOptions:: 717 SyntheticChildrenTraversal::Both); 718 ValueObject *target = nullptr; 719 const char *var_name_final_if_array_range = nullptr; 720 size_t close_bracket_index = llvm::StringRef::npos; 721 int64_t index_lower = -1; 722 int64_t index_higher = -1; 723 bool is_array_range = false; 724 bool was_plain_var = false; 725 bool was_var_format = false; 726 bool was_var_indexed = false; 727 ValueObject::ExpressionPathScanEndReason reason_to_stop = 728 ValueObject::eExpressionPathScanEndReasonEndOfString; 729 ValueObject::ExpressionPathEndResultType final_value_type = 730 ValueObject::eExpressionPathEndResultTypePlain; 731 732 if (is_script) { 733 return RunScriptFormatKeyword(s, sc, exe_ctx, valobj, entry.string.c_str()); 734 } 735 736 llvm::StringRef subpath(entry.string); 737 // simplest case ${var}, just print valobj's value 738 if (entry.string.empty()) { 739 if (entry.printf_format.empty() && entry.fmt == eFormatDefault && 740 entry.number == ValueObject::eValueObjectRepresentationStyleValue) 741 was_plain_var = true; 742 else 743 was_var_format = true; 744 target = valobj; 745 } else // this is ${var.something} or multiple .something nested 746 { 747 if (entry.string[0] == '[') 748 was_var_indexed = true; 749 ScanBracketedRange(subpath, close_bracket_index, 750 var_name_final_if_array_range, index_lower, 751 index_higher); 752 753 Error error; 754 755 const std::string &expr_path = entry.string; 756 757 if (log) 758 log->Printf("[Debugger::FormatPrompt] symbol to expand: %s", 759 expr_path.c_str()); 760 761 target = 762 valobj 763 ->GetValueForExpressionPath(expr_path.c_str(), &reason_to_stop, 764 &final_value_type, options, &what_next) 765 .get(); 766 767 if (!target) { 768 if (log) 769 log->Printf("[Debugger::FormatPrompt] ERROR: why stopping = %d," 770 " final_value_type %d", 771 reason_to_stop, final_value_type); 772 return false; 773 } else { 774 if (log) 775 log->Printf("[Debugger::FormatPrompt] ALL RIGHT: why stopping = %d," 776 " final_value_type %d", 777 reason_to_stop, final_value_type); 778 target = target 779 ->GetQualifiedRepresentationIfAvailable( 780 target->GetDynamicValueType(), true) 781 .get(); 782 } 783 } 784 785 is_array_range = 786 (final_value_type == 787 ValueObject::eExpressionPathEndResultTypeBoundedRange || 788 final_value_type == 789 ValueObject::eExpressionPathEndResultTypeUnboundedRange); 790 791 do_deref_pointer = 792 (what_next == ValueObject::eExpressionPathAftermathDereference); 793 794 if (do_deref_pointer && !is_array_range) { 795 // I have not deref-ed yet, let's do it 796 // this happens when we are not going through 797 // GetValueForVariableExpressionPath 798 // to get to the target ValueObject 799 Error error; 800 target = target->Dereference(error).get(); 801 if (error.Fail()) { 802 if (log) 803 log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", 804 error.AsCString("unknown")); 805 return false; 806 } 807 do_deref_pointer = false; 808 } 809 810 if (!target) { 811 if (log) 812 log->Printf("[Debugger::FormatPrompt] could not calculate target for " 813 "prompt expression"); 814 return false; 815 } 816 817 // we do not want to use the summary for a bitfield of type T:n 818 // if we were originally dealing with just a T - that would get 819 // us into an endless recursion 820 if (target->IsBitfield() && was_var_indexed) { 821 // TODO: check for a (T:n)-specific summary - we should still obey that 822 StreamString bitfield_name; 823 bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), 824 target->GetBitfieldBitSize()); 825 lldb::TypeNameSpecifierImplSP type_sp( 826 new TypeNameSpecifierImpl(bitfield_name.GetString(), false)); 827 if (val_obj_display == 828 ValueObject::eValueObjectRepresentationStyleSummary && 829 !DataVisualization::GetSummaryForType(type_sp)) 830 val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 831 } 832 833 // TODO use flags for these 834 const uint32_t type_info_flags = 835 target->GetCompilerType().GetTypeInfo(nullptr); 836 bool is_array = (type_info_flags & eTypeIsArray) != 0; 837 bool is_pointer = (type_info_flags & eTypeIsPointer) != 0; 838 bool is_aggregate = target->GetCompilerType().IsAggregateType(); 839 840 if ((is_array || is_pointer) && (!is_array_range) && 841 val_obj_display == 842 ValueObject::eValueObjectRepresentationStyleValue) // this should be 843 // wrong, but there 844 // are some 845 // exceptions 846 { 847 StreamString str_temp; 848 if (log) 849 log->Printf( 850 "[Debugger::FormatPrompt] I am into array || pointer && !range"); 851 852 if (target->HasSpecialPrintableRepresentation(val_obj_display, 853 custom_format)) { 854 // try to use the special cases 855 bool success = target->DumpPrintableRepresentation( 856 str_temp, val_obj_display, custom_format); 857 if (log) 858 log->Printf("[Debugger::FormatPrompt] special cases did%s match", 859 success ? "" : "n't"); 860 861 // should not happen 862 if (success) 863 s << str_temp.GetString(); 864 return true; 865 } else { 866 if (was_plain_var) // if ${var} 867 { 868 s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); 869 } else if (is_pointer) // if pointer, value is the address stored 870 { 871 target->DumpPrintableRepresentation( 872 s, val_obj_display, custom_format, 873 ValueObject::PrintableRepresentationSpecialCases::eDisable); 874 } 875 return true; 876 } 877 } 878 879 // if directly trying to print ${var}, and this is an aggregate, display a 880 // nice 881 // type @ location message 882 if (is_aggregate && was_plain_var) { 883 s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); 884 return true; 885 } 886 887 // if directly trying to print ${var%V}, and this is an aggregate, do not let 888 // the user do it 889 if (is_aggregate && 890 ((was_var_format && 891 val_obj_display == 892 ValueObject::eValueObjectRepresentationStyleValue))) { 893 s << "<invalid use of aggregate type>"; 894 return true; 895 } 896 897 if (!is_array_range) { 898 if (log) 899 log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output"); 900 return target->DumpPrintableRepresentation(s, val_obj_display, 901 custom_format); 902 } else { 903 if (log) 904 log->Printf("[Debugger::FormatPrompt] checking if I can handle as array"); 905 if (!is_array && !is_pointer) 906 return false; 907 if (log) 908 log->Printf("[Debugger::FormatPrompt] handle as array"); 909 StreamString special_directions_stream; 910 llvm::StringRef special_directions; 911 if (close_bracket_index != llvm::StringRef::npos && 912 subpath.size() > close_bracket_index) { 913 ConstString additional_data(subpath.drop_front(close_bracket_index + 1)); 914 special_directions_stream.Printf("${%svar%s", do_deref_pointer ? "*" : "", 915 additional_data.GetCString()); 916 917 if (entry.fmt != eFormatDefault) { 918 const char format_char = 919 FormatManager::GetFormatAsFormatChar(entry.fmt); 920 if (format_char != '\0') 921 special_directions_stream.Printf("%%%c", format_char); 922 else { 923 const char *format_cstr = 924 FormatManager::GetFormatAsCString(entry.fmt); 925 special_directions_stream.Printf("%%%s", format_cstr); 926 } 927 } else if (entry.number != 0) { 928 const char style_char = ConvertValueObjectStyleToChar( 929 (ValueObject::ValueObjectRepresentationStyle)entry.number); 930 if (style_char) 931 special_directions_stream.Printf("%%%c", style_char); 932 } 933 special_directions_stream.PutChar('}'); 934 special_directions = 935 llvm::StringRef(special_directions_stream.GetString()); 936 } 937 938 // let us display items index_lower thru index_higher of this array 939 s.PutChar('['); 940 941 if (index_higher < 0) 942 index_higher = valobj->GetNumChildren() - 1; 943 944 uint32_t max_num_children = 945 target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 946 947 bool success = true; 948 for (int64_t index = index_lower; index <= index_higher; ++index) { 949 ValueObject *item = 950 ExpandIndexedExpression(target, index, exe_ctx->GetFramePtr(), false) 951 .get(); 952 953 if (!item) { 954 if (log) 955 log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at " 956 "index %" PRId64, 957 index); 958 } else { 959 if (log) 960 log->Printf( 961 "[Debugger::FormatPrompt] special_directions for child item: %s", 962 special_directions.data() ? special_directions.data() : ""); 963 } 964 965 if (special_directions.empty()) { 966 success &= item->DumpPrintableRepresentation(s, val_obj_display, 967 custom_format); 968 } else { 969 success &= FormatEntity::FormatStringRef( 970 special_directions, s, sc, exe_ctx, nullptr, item, false, false); 971 } 972 973 if (--max_num_children == 0) { 974 s.PutCString(", ..."); 975 break; 976 } 977 978 if (index < index_higher) 979 s.PutChar(','); 980 } 981 s.PutChar(']'); 982 return success; 983 } 984 } 985 986 static bool DumpRegister(Stream &s, StackFrame *frame, const char *reg_name, 987 Format format) { 988 if (frame) { 989 RegisterContext *reg_ctx = frame->GetRegisterContext().get(); 990 991 if (reg_ctx) { 992 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 993 if (reg_info) { 994 RegisterValue reg_value; 995 if (reg_ctx->ReadRegister(reg_info, reg_value)) { 996 reg_value.Dump(&s, reg_info, false, false, format); 997 return true; 998 } 999 } 1000 } 1001 } 1002 return false; 1003 } 1004 1005 static bool FormatThreadExtendedInfoRecurse( 1006 const FormatEntity::Entry &entry, 1007 const StructuredData::ObjectSP &thread_info_dictionary, 1008 const SymbolContext *sc, const ExecutionContext *exe_ctx, Stream &s) { 1009 llvm::StringRef path(entry.string); 1010 1011 StructuredData::ObjectSP value = 1012 thread_info_dictionary->GetObjectForDotSeparatedPath(path); 1013 1014 if (value) { 1015 if (value->GetType() == StructuredData::Type::eTypeInteger) { 1016 const char *token_format = "0x%4.4" PRIx64; 1017 if (!entry.printf_format.empty()) 1018 token_format = entry.printf_format.c_str(); 1019 s.Printf(token_format, value->GetAsInteger()->GetValue()); 1020 return true; 1021 } else if (value->GetType() == StructuredData::Type::eTypeFloat) { 1022 s.Printf("%f", value->GetAsFloat()->GetValue()); 1023 return true; 1024 } else if (value->GetType() == StructuredData::Type::eTypeString) { 1025 s.Printf("%s", value->GetAsString()->GetValue().c_str()); 1026 return true; 1027 } else if (value->GetType() == StructuredData::Type::eTypeArray) { 1028 if (value->GetAsArray()->GetSize() > 0) { 1029 s.Printf("%zu", value->GetAsArray()->GetSize()); 1030 return true; 1031 } 1032 } else if (value->GetType() == StructuredData::Type::eTypeDictionary) { 1033 s.Printf("%zu", 1034 value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); 1035 return true; 1036 } 1037 } 1038 1039 return false; 1040 } 1041 1042 static inline bool IsToken(const char *var_name_begin, const char *var) { 1043 return (::strncmp(var_name_begin, var, strlen(var)) == 0); 1044 } 1045 1046 bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s, 1047 const SymbolContext *sc, 1048 const ExecutionContext *exe_ctx, 1049 const Address *addr, ValueObject *valobj, 1050 bool function_changed, 1051 bool initial_function) { 1052 if (!format_str.empty()) { 1053 FormatEntity::Entry root; 1054 Error error = FormatEntity::Parse(format_str, root); 1055 if (error.Success()) { 1056 return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj, 1057 function_changed, initial_function); 1058 } 1059 } 1060 return false; 1061 } 1062 1063 bool FormatEntity::FormatCString(const char *format, Stream &s, 1064 const SymbolContext *sc, 1065 const ExecutionContext *exe_ctx, 1066 const Address *addr, ValueObject *valobj, 1067 bool function_changed, bool initial_function) { 1068 if (format && format[0]) { 1069 FormatEntity::Entry root; 1070 llvm::StringRef format_str(format); 1071 Error error = FormatEntity::Parse(format_str, root); 1072 if (error.Success()) { 1073 return FormatEntity::Format(root, s, sc, exe_ctx, addr, valobj, 1074 function_changed, initial_function); 1075 } 1076 } 1077 return false; 1078 } 1079 1080 bool FormatEntity::Format(const Entry &entry, Stream &s, 1081 const SymbolContext *sc, 1082 const ExecutionContext *exe_ctx, const Address *addr, 1083 ValueObject *valobj, bool function_changed, 1084 bool initial_function) { 1085 switch (entry.type) { 1086 case Entry::Type::Invalid: 1087 case Entry::Type::ParentNumber: // Only used for 1088 // FormatEntity::Entry::Definition encoding 1089 case Entry::Type::ParentString: // Only used for 1090 // FormatEntity::Entry::Definition encoding 1091 case Entry::Type::InsertString: // Only used for 1092 // FormatEntity::Entry::Definition encoding 1093 return false; 1094 1095 case Entry::Type::Root: 1096 for (const auto &child : entry.children) { 1097 if (!Format(child, s, sc, exe_ctx, addr, valobj, function_changed, 1098 initial_function)) { 1099 return false; // If any item of root fails, then the formatting fails 1100 } 1101 } 1102 return true; // Only return true if all items succeeded 1103 1104 case Entry::Type::String: 1105 s.PutCString(entry.string); 1106 return true; 1107 1108 case Entry::Type::Scope: { 1109 StreamString scope_stream; 1110 bool success = false; 1111 for (const auto &child : entry.children) { 1112 success = Format(child, scope_stream, sc, exe_ctx, addr, valobj, 1113 function_changed, initial_function); 1114 if (!success) 1115 break; 1116 } 1117 // Only if all items in a scope succeed, then do we 1118 // print the output into the main stream 1119 if (success) 1120 s.Write(scope_stream.GetString().data(), scope_stream.GetString().size()); 1121 } 1122 return true; // Scopes always successfully print themselves 1123 1124 case Entry::Type::Variable: 1125 case Entry::Type::VariableSynthetic: 1126 case Entry::Type::ScriptVariable: 1127 case Entry::Type::ScriptVariableSynthetic: 1128 return DumpValue(s, sc, exe_ctx, entry, valobj); 1129 1130 case Entry::Type::AddressFile: 1131 case Entry::Type::AddressLoad: 1132 case Entry::Type::AddressLoadOrFile: 1133 return (addr != nullptr && addr->IsValid() && 1134 DumpAddress(s, sc, exe_ctx, *addr, 1135 entry.type == Entry::Type::AddressLoadOrFile)); 1136 1137 case Entry::Type::ProcessID: 1138 if (exe_ctx) { 1139 Process *process = exe_ctx->GetProcessPtr(); 1140 if (process) { 1141 const char *format = "%" PRIu64; 1142 if (!entry.printf_format.empty()) 1143 format = entry.printf_format.c_str(); 1144 s.Printf(format, process->GetID()); 1145 return true; 1146 } 1147 } 1148 return false; 1149 1150 case Entry::Type::ProcessFile: 1151 if (exe_ctx) { 1152 Process *process = exe_ctx->GetProcessPtr(); 1153 if (process) { 1154 Module *exe_module = process->GetTarget().GetExecutableModulePointer(); 1155 if (exe_module) { 1156 if (DumpFile(s, exe_module->GetFileSpec(), (FileKind)entry.number)) 1157 return true; 1158 } 1159 } 1160 } 1161 return false; 1162 1163 case Entry::Type::ScriptProcess: 1164 if (exe_ctx) { 1165 Process *process = exe_ctx->GetProcessPtr(); 1166 if (process) 1167 return RunScriptFormatKeyword(s, sc, exe_ctx, process, 1168 entry.string.c_str()); 1169 } 1170 return false; 1171 1172 case Entry::Type::ThreadID: 1173 if (exe_ctx) { 1174 Thread *thread = exe_ctx->GetThreadPtr(); 1175 if (thread) { 1176 const char *format = "0x%4.4" PRIx64; 1177 if (!entry.printf_format.empty()) { 1178 // Watch for the special "tid" format... 1179 if (entry.printf_format == "tid") { 1180 // TODO(zturner): Rather than hardcoding this to be platform 1181 // specific, it should be controlled by a 1182 // setting and the default value of the setting can be different 1183 // depending on the platform. 1184 Target &target = thread->GetProcess()->GetTarget(); 1185 ArchSpec arch(target.GetArchitecture()); 1186 llvm::Triple::OSType ostype = arch.IsValid() 1187 ? arch.GetTriple().getOS() 1188 : llvm::Triple::UnknownOS; 1189 if ((ostype == llvm::Triple::FreeBSD) || 1190 (ostype == llvm::Triple::Linux) || 1191 (ostype == llvm::Triple::NetBSD)) { 1192 format = "%" PRIu64; 1193 } 1194 } else { 1195 format = entry.printf_format.c_str(); 1196 } 1197 } 1198 s.Printf(format, thread->GetID()); 1199 return true; 1200 } 1201 } 1202 return false; 1203 1204 case Entry::Type::ThreadProtocolID: 1205 if (exe_ctx) { 1206 Thread *thread = exe_ctx->GetThreadPtr(); 1207 if (thread) { 1208 const char *format = "0x%4.4" PRIx64; 1209 if (!entry.printf_format.empty()) 1210 format = entry.printf_format.c_str(); 1211 s.Printf(format, thread->GetProtocolID()); 1212 return true; 1213 } 1214 } 1215 return false; 1216 1217 case Entry::Type::ThreadIndexID: 1218 if (exe_ctx) { 1219 Thread *thread = exe_ctx->GetThreadPtr(); 1220 if (thread) { 1221 const char *format = "%" PRIu32; 1222 if (!entry.printf_format.empty()) 1223 format = entry.printf_format.c_str(); 1224 s.Printf(format, thread->GetIndexID()); 1225 return true; 1226 } 1227 } 1228 return false; 1229 1230 case Entry::Type::ThreadName: 1231 if (exe_ctx) { 1232 Thread *thread = exe_ctx->GetThreadPtr(); 1233 if (thread) { 1234 const char *cstr = thread->GetName(); 1235 if (cstr && cstr[0]) { 1236 s.PutCString(cstr); 1237 return true; 1238 } 1239 } 1240 } 1241 return false; 1242 1243 case Entry::Type::ThreadQueue: 1244 if (exe_ctx) { 1245 Thread *thread = exe_ctx->GetThreadPtr(); 1246 if (thread) { 1247 const char *cstr = thread->GetQueueName(); 1248 if (cstr && cstr[0]) { 1249 s.PutCString(cstr); 1250 return true; 1251 } 1252 } 1253 } 1254 return false; 1255 1256 case Entry::Type::ThreadStopReason: 1257 if (exe_ctx) { 1258 Thread *thread = exe_ctx->GetThreadPtr(); 1259 if (thread) { 1260 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1261 if (stop_info_sp && stop_info_sp->IsValid()) { 1262 const char *cstr = stop_info_sp->GetDescription(); 1263 if (cstr && cstr[0]) { 1264 s.PutCString(cstr); 1265 return true; 1266 } 1267 } 1268 } 1269 } 1270 return false; 1271 1272 case Entry::Type::ThreadReturnValue: 1273 if (exe_ctx) { 1274 Thread *thread = exe_ctx->GetThreadPtr(); 1275 if (thread) { 1276 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1277 if (stop_info_sp && stop_info_sp->IsValid()) { 1278 ValueObjectSP return_valobj_sp = 1279 StopInfo::GetReturnValueObject(stop_info_sp); 1280 if (return_valobj_sp) { 1281 return_valobj_sp->Dump(s); 1282 return true; 1283 } 1284 } 1285 } 1286 } 1287 return false; 1288 1289 case Entry::Type::ThreadCompletedExpression: 1290 if (exe_ctx) { 1291 Thread *thread = exe_ctx->GetThreadPtr(); 1292 if (thread) { 1293 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1294 if (stop_info_sp && stop_info_sp->IsValid()) { 1295 ExpressionVariableSP expression_var_sp = 1296 StopInfo::GetExpressionVariable(stop_info_sp); 1297 if (expression_var_sp && expression_var_sp->GetValueObject()) { 1298 expression_var_sp->GetValueObject()->Dump(s); 1299 return true; 1300 } 1301 } 1302 } 1303 } 1304 return false; 1305 1306 case Entry::Type::ScriptThread: 1307 if (exe_ctx) { 1308 Thread *thread = exe_ctx->GetThreadPtr(); 1309 if (thread) 1310 return RunScriptFormatKeyword(s, sc, exe_ctx, thread, 1311 entry.string.c_str()); 1312 } 1313 return false; 1314 1315 case Entry::Type::ThreadInfo: 1316 if (exe_ctx) { 1317 Thread *thread = exe_ctx->GetThreadPtr(); 1318 if (thread) { 1319 StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); 1320 if (object_sp && 1321 object_sp->GetType() == StructuredData::Type::eTypeDictionary) { 1322 if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s)) 1323 return true; 1324 } 1325 } 1326 } 1327 return false; 1328 1329 case Entry::Type::TargetArch: 1330 if (exe_ctx) { 1331 Target *target = exe_ctx->GetTargetPtr(); 1332 if (target) { 1333 const ArchSpec &arch = target->GetArchitecture(); 1334 if (arch.IsValid()) { 1335 s.PutCString(arch.GetArchitectureName()); 1336 return true; 1337 } 1338 } 1339 } 1340 return false; 1341 1342 case Entry::Type::ScriptTarget: 1343 if (exe_ctx) { 1344 Target *target = exe_ctx->GetTargetPtr(); 1345 if (target) 1346 return RunScriptFormatKeyword(s, sc, exe_ctx, target, 1347 entry.string.c_str()); 1348 } 1349 return false; 1350 1351 case Entry::Type::ModuleFile: 1352 if (sc) { 1353 Module *module = sc->module_sp.get(); 1354 if (module) { 1355 if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number)) 1356 return true; 1357 } 1358 } 1359 return false; 1360 1361 case Entry::Type::File: 1362 if (sc) { 1363 CompileUnit *cu = sc->comp_unit; 1364 if (cu) { 1365 // CompileUnit is a FileSpec 1366 if (DumpFile(s, *cu, (FileKind)entry.number)) 1367 return true; 1368 } 1369 } 1370 return false; 1371 1372 case Entry::Type::Lang: 1373 if (sc) { 1374 CompileUnit *cu = sc->comp_unit; 1375 if (cu) { 1376 const char *lang_name = 1377 Language::GetNameForLanguageType(cu->GetLanguage()); 1378 if (lang_name) { 1379 s.PutCString(lang_name); 1380 return true; 1381 } 1382 } 1383 } 1384 return false; 1385 1386 case Entry::Type::FrameIndex: 1387 if (exe_ctx) { 1388 StackFrame *frame = exe_ctx->GetFramePtr(); 1389 if (frame) { 1390 const char *format = "%" PRIu32; 1391 if (!entry.printf_format.empty()) 1392 format = entry.printf_format.c_str(); 1393 s.Printf(format, frame->GetFrameIndex()); 1394 return true; 1395 } 1396 } 1397 return false; 1398 1399 case Entry::Type::FrameRegisterPC: 1400 if (exe_ctx) { 1401 StackFrame *frame = exe_ctx->GetFramePtr(); 1402 if (frame) { 1403 const Address &pc_addr = frame->GetFrameCodeAddress(); 1404 if (pc_addr.IsValid()) { 1405 if (DumpAddress(s, sc, exe_ctx, pc_addr, false)) 1406 return true; 1407 } 1408 } 1409 } 1410 return false; 1411 1412 case Entry::Type::FrameRegisterSP: 1413 if (exe_ctx) { 1414 StackFrame *frame = exe_ctx->GetFramePtr(); 1415 if (frame) { 1416 if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 1417 (lldb::Format)entry.number)) 1418 return true; 1419 } 1420 } 1421 return false; 1422 1423 case Entry::Type::FrameRegisterFP: 1424 if (exe_ctx) { 1425 StackFrame *frame = exe_ctx->GetFramePtr(); 1426 if (frame) { 1427 if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, 1428 (lldb::Format)entry.number)) 1429 return true; 1430 } 1431 } 1432 return false; 1433 1434 case Entry::Type::FrameRegisterFlags: 1435 if (exe_ctx) { 1436 StackFrame *frame = exe_ctx->GetFramePtr(); 1437 if (frame) { 1438 if (DumpRegister(s, frame, eRegisterKindGeneric, 1439 LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number)) 1440 return true; 1441 } 1442 } 1443 return false; 1444 1445 case Entry::Type::FrameNoDebug: 1446 if (exe_ctx) { 1447 StackFrame *frame = exe_ctx->GetFramePtr(); 1448 if (frame) { 1449 return !frame->HasDebugInformation(); 1450 } 1451 } 1452 return true; 1453 1454 case Entry::Type::FrameRegisterByName: 1455 if (exe_ctx) { 1456 StackFrame *frame = exe_ctx->GetFramePtr(); 1457 if (frame) { 1458 if (DumpRegister(s, frame, entry.string.c_str(), 1459 (lldb::Format)entry.number)) 1460 return true; 1461 } 1462 } 1463 return false; 1464 1465 case Entry::Type::ScriptFrame: 1466 if (exe_ctx) { 1467 StackFrame *frame = exe_ctx->GetFramePtr(); 1468 if (frame) 1469 return RunScriptFormatKeyword(s, sc, exe_ctx, frame, 1470 entry.string.c_str()); 1471 } 1472 return false; 1473 1474 case Entry::Type::FunctionID: 1475 if (sc) { 1476 if (sc->function) { 1477 s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); 1478 return true; 1479 } else if (sc->symbol) { 1480 s.Printf("symbol[%u]", sc->symbol->GetID()); 1481 return true; 1482 } 1483 } 1484 return false; 1485 1486 case Entry::Type::FunctionDidChange: 1487 return function_changed; 1488 1489 case Entry::Type::FunctionInitialFunction: 1490 return initial_function; 1491 1492 case Entry::Type::FunctionName: { 1493 Language *language_plugin = nullptr; 1494 bool language_plugin_handled = false; 1495 StreamString ss; 1496 if (sc->function) 1497 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1498 else if (sc->symbol) 1499 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1500 if (language_plugin) { 1501 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1502 sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss); 1503 } 1504 if (language_plugin_handled) { 1505 s << ss.GetString(); 1506 return true; 1507 } else { 1508 const char *name = nullptr; 1509 if (sc->function) 1510 name = sc->function->GetName().AsCString(nullptr); 1511 else if (sc->symbol) 1512 name = sc->symbol->GetName().AsCString(nullptr); 1513 if (name) { 1514 s.PutCString(name); 1515 1516 if (sc->block) { 1517 Block *inline_block = sc->block->GetContainingInlinedBlock(); 1518 if (inline_block) { 1519 const InlineFunctionInfo *inline_info = 1520 sc->block->GetInlinedFunctionInfo(); 1521 if (inline_info) { 1522 s.PutCString(" [inlined] "); 1523 inline_info->GetName(sc->function->GetLanguage()).Dump(&s); 1524 } 1525 } 1526 } 1527 return true; 1528 } 1529 } 1530 } 1531 return false; 1532 1533 case Entry::Type::FunctionNameNoArgs: { 1534 Language *language_plugin = nullptr; 1535 bool language_plugin_handled = false; 1536 StreamString ss; 1537 if (sc->function) 1538 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1539 else if (sc->symbol) 1540 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1541 if (language_plugin) { 1542 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1543 sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs, 1544 ss); 1545 } 1546 if (language_plugin_handled) { 1547 s << ss.GetString(); 1548 return true; 1549 } else { 1550 ConstString name; 1551 if (sc->function) 1552 name = sc->function->GetNameNoArguments(); 1553 else if (sc->symbol) 1554 name = sc->symbol->GetNameNoArguments(); 1555 if (name) { 1556 s.PutCString(name.GetCString()); 1557 return true; 1558 } 1559 } 1560 } 1561 return false; 1562 1563 case Entry::Type::FunctionNameWithArgs: { 1564 Language *language_plugin = nullptr; 1565 bool language_plugin_handled = false; 1566 StreamString ss; 1567 if (sc->function) 1568 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1569 else if (sc->symbol) 1570 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1571 if (language_plugin) { 1572 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1573 sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss); 1574 } 1575 if (language_plugin_handled) { 1576 s << ss.GetString(); 1577 return true; 1578 } else { 1579 // Print the function name with arguments in it 1580 if (sc->function) { 1581 ExecutionContextScope *exe_scope = 1582 exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; 1583 const char *cstr = sc->function->GetName().AsCString(nullptr); 1584 if (cstr) { 1585 const InlineFunctionInfo *inline_info = nullptr; 1586 VariableListSP variable_list_sp; 1587 bool get_function_vars = true; 1588 if (sc->block) { 1589 Block *inline_block = sc->block->GetContainingInlinedBlock(); 1590 1591 if (inline_block) { 1592 get_function_vars = false; 1593 inline_info = sc->block->GetInlinedFunctionInfo(); 1594 if (inline_info) 1595 variable_list_sp = inline_block->GetBlockVariableList(true); 1596 } 1597 } 1598 1599 if (get_function_vars) { 1600 variable_list_sp = 1601 sc->function->GetBlock(true).GetBlockVariableList(true); 1602 } 1603 1604 if (inline_info) { 1605 s.PutCString(cstr); 1606 s.PutCString(" [inlined] "); 1607 cstr = 1608 inline_info->GetName(sc->function->GetLanguage()).GetCString(); 1609 } 1610 1611 VariableList args; 1612 if (variable_list_sp) 1613 variable_list_sp->AppendVariablesWithScope( 1614 eValueTypeVariableArgument, args); 1615 if (args.GetSize() > 0) { 1616 const char *open_paren = strchr(cstr, '('); 1617 const char *close_paren = nullptr; 1618 const char *generic = strchr(cstr, '<'); 1619 // if before the arguments list begins there is a template sign 1620 // then scan to the end of the generic args before you try to find 1621 // the arguments list 1622 if (generic && open_paren && generic < open_paren) { 1623 int generic_depth = 1; 1624 ++generic; 1625 for (; *generic && generic_depth > 0; generic++) { 1626 if (*generic == '<') 1627 generic_depth++; 1628 if (*generic == '>') 1629 generic_depth--; 1630 } 1631 if (*generic) 1632 open_paren = strchr(generic, '('); 1633 else 1634 open_paren = nullptr; 1635 } 1636 if (open_paren) { 1637 if (IsToken(open_paren, "(anonymous namespace)")) { 1638 open_paren = 1639 strchr(open_paren + strlen("(anonymous namespace)"), '('); 1640 if (open_paren) 1641 close_paren = strchr(open_paren, ')'); 1642 } else 1643 close_paren = strchr(open_paren, ')'); 1644 } 1645 1646 if (open_paren) 1647 s.Write(cstr, open_paren - cstr + 1); 1648 else { 1649 s.PutCString(cstr); 1650 s.PutChar('('); 1651 } 1652 const size_t num_args = args.GetSize(); 1653 for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) { 1654 std::string buffer; 1655 1656 VariableSP var_sp(args.GetVariableAtIndex(arg_idx)); 1657 ValueObjectSP var_value_sp( 1658 ValueObjectVariable::Create(exe_scope, var_sp)); 1659 StreamString ss; 1660 llvm::StringRef var_representation; 1661 const char *var_name = var_value_sp->GetName().GetCString(); 1662 if (var_value_sp->GetCompilerType().IsValid()) { 1663 if (var_value_sp && exe_scope->CalculateTarget()) 1664 var_value_sp = 1665 var_value_sp->GetQualifiedRepresentationIfAvailable( 1666 exe_scope->CalculateTarget() 1667 ->TargetProperties::GetPreferDynamicValue(), 1668 exe_scope->CalculateTarget() 1669 ->TargetProperties::GetEnableSyntheticValue()); 1670 if (var_value_sp->GetCompilerType().IsAggregateType() && 1671 DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) { 1672 static StringSummaryFormat format( 1673 TypeSummaryImpl::Flags() 1674 .SetHideItemNames(false) 1675 .SetShowMembersOneLiner(true), 1676 ""); 1677 format.FormatObject(var_value_sp.get(), buffer, 1678 TypeSummaryOptions()); 1679 var_representation = buffer; 1680 } else 1681 var_value_sp->DumpPrintableRepresentation( 1682 ss, ValueObject::ValueObjectRepresentationStyle:: 1683 eValueObjectRepresentationStyleSummary, 1684 eFormatDefault, 1685 ValueObject::PrintableRepresentationSpecialCases::eAllow, 1686 false); 1687 } 1688 1689 if (!ss.GetString().empty()) 1690 var_representation = ss.GetString(); 1691 if (arg_idx > 0) 1692 s.PutCString(", "); 1693 if (var_value_sp->GetError().Success()) { 1694 if (!var_representation.empty()) 1695 s.Printf("%s=%s", var_name, var_representation.str().c_str()); 1696 else 1697 s.Printf("%s=%s at %s", var_name, 1698 var_value_sp->GetTypeName().GetCString(), 1699 var_value_sp->GetLocationAsCString()); 1700 } else 1701 s.Printf("%s=<unavailable>", var_name); 1702 } 1703 1704 if (close_paren) 1705 s.PutCString(close_paren); 1706 else 1707 s.PutChar(')'); 1708 1709 } else { 1710 s.PutCString(cstr); 1711 } 1712 return true; 1713 } 1714 } else if (sc->symbol) { 1715 const char *cstr = sc->symbol->GetName().AsCString(nullptr); 1716 if (cstr) { 1717 s.PutCString(cstr); 1718 return true; 1719 } 1720 } 1721 } 1722 } 1723 return false; 1724 1725 case Entry::Type::FunctionAddrOffset: 1726 if (addr) { 1727 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false, 1728 false)) 1729 return true; 1730 } 1731 return false; 1732 1733 case Entry::Type::FunctionAddrOffsetConcrete: 1734 if (addr) { 1735 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, true, true, 1736 true)) 1737 return true; 1738 } 1739 return false; 1740 1741 case Entry::Type::FunctionLineOffset: 1742 return (DumpAddressOffsetFromFunction(s, sc, exe_ctx, 1743 sc->line_entry.range.GetBaseAddress(), 1744 false, false, false)); 1745 1746 case Entry::Type::FunctionPCOffset: 1747 if (exe_ctx) { 1748 StackFrame *frame = exe_ctx->GetFramePtr(); 1749 if (frame) { 1750 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, 1751 frame->GetFrameCodeAddress(), false, 1752 false, false)) 1753 return true; 1754 } 1755 } 1756 return false; 1757 1758 case Entry::Type::FunctionChanged: 1759 return function_changed; 1760 1761 case Entry::Type::FunctionIsOptimized: { 1762 bool is_optimized = false; 1763 if (sc->function && sc->function->GetIsOptimized()) { 1764 is_optimized = true; 1765 } 1766 return is_optimized; 1767 } 1768 1769 case Entry::Type::FunctionInitial: 1770 return initial_function; 1771 1772 case Entry::Type::LineEntryFile: 1773 if (sc && sc->line_entry.IsValid()) { 1774 Module *module = sc->module_sp.get(); 1775 if (module) { 1776 if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number)) 1777 return true; 1778 } 1779 } 1780 return false; 1781 1782 case Entry::Type::LineEntryLineNumber: 1783 if (sc && sc->line_entry.IsValid()) { 1784 const char *format = "%" PRIu32; 1785 if (!entry.printf_format.empty()) 1786 format = entry.printf_format.c_str(); 1787 s.Printf(format, sc->line_entry.line); 1788 return true; 1789 } 1790 return false; 1791 1792 case Entry::Type::LineEntryStartAddress: 1793 case Entry::Type::LineEntryEndAddress: 1794 if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) { 1795 Address addr = sc->line_entry.range.GetBaseAddress(); 1796 1797 if (entry.type == Entry::Type::LineEntryEndAddress) 1798 addr.Slide(sc->line_entry.range.GetByteSize()); 1799 if (DumpAddress(s, sc, exe_ctx, addr, false)) 1800 return true; 1801 } 1802 return false; 1803 1804 case Entry::Type::CurrentPCArrow: 1805 if (addr && exe_ctx && exe_ctx->GetFramePtr()) { 1806 RegisterContextSP reg_ctx = 1807 exe_ctx->GetFramePtr()->GetRegisterContextSP(); 1808 if (reg_ctx) { 1809 addr_t pc_loadaddr = reg_ctx->GetPC(); 1810 if (pc_loadaddr != LLDB_INVALID_ADDRESS) { 1811 Address pc; 1812 pc.SetLoadAddress(pc_loadaddr, exe_ctx->GetTargetPtr()); 1813 if (pc == *addr) { 1814 s.Printf("-> "); 1815 return true; 1816 } 1817 } 1818 } 1819 s.Printf(" "); 1820 return true; 1821 } 1822 return false; 1823 } 1824 return false; 1825 } 1826 1827 static bool DumpCommaSeparatedChildEntryNames( 1828 Stream &s, const FormatEntity::Entry::Definition *parent) { 1829 if (parent->children) { 1830 const size_t n = parent->num_children; 1831 for (size_t i = 0; i < n; ++i) { 1832 if (i > 0) 1833 s.PutCString(", "); 1834 s.Printf("\"%s\"", parent->children[i].name); 1835 } 1836 return true; 1837 } 1838 return false; 1839 } 1840 1841 static Error ParseEntry(const llvm::StringRef &format_str, 1842 const FormatEntity::Entry::Definition *parent, 1843 FormatEntity::Entry &entry) { 1844 Error error; 1845 1846 const size_t sep_pos = format_str.find_first_of(".[:"); 1847 const char sep_char = 1848 (sep_pos == llvm::StringRef::npos) ? '\0' : format_str[sep_pos]; 1849 llvm::StringRef key = format_str.substr(0, sep_pos); 1850 1851 const size_t n = parent->num_children; 1852 for (size_t i = 0; i < n; ++i) { 1853 const FormatEntity::Entry::Definition *entry_def = parent->children + i; 1854 if (key.equals(entry_def->name) || entry_def->name[0] == '*') { 1855 llvm::StringRef value; 1856 if (sep_char) 1857 value = 1858 format_str.substr(sep_pos + (entry_def->keep_separator ? 0 : 1)); 1859 switch (entry_def->type) { 1860 case FormatEntity::Entry::Type::ParentString: 1861 entry.string = format_str.str(); 1862 return error; // Success 1863 1864 case FormatEntity::Entry::Type::ParentNumber: 1865 entry.number = entry_def->data; 1866 return error; // Success 1867 1868 case FormatEntity::Entry::Type::InsertString: 1869 entry.type = entry_def->type; 1870 entry.string = entry_def->string; 1871 return error; // Success 1872 1873 default: 1874 entry.type = entry_def->type; 1875 break; 1876 } 1877 1878 if (value.empty()) { 1879 if (entry_def->type == FormatEntity::Entry::Type::Invalid) { 1880 if (entry_def->children) { 1881 StreamString error_strm; 1882 error_strm.Printf("'%s' can't be specified on its own, you must " 1883 "access one of its children: ", 1884 entry_def->name); 1885 DumpCommaSeparatedChildEntryNames(error_strm, entry_def); 1886 error.SetErrorStringWithFormat("%s", error_strm.GetData()); 1887 } else if (sep_char == ':') { 1888 // Any value whose separator is a with a ':' means this value has a 1889 // string argument 1890 // that needs to be stored in the entry (like "${script.var:}"). 1891 // In this case the string value is the empty string which is ok. 1892 } else { 1893 error.SetErrorStringWithFormat("%s", "invalid entry definitions"); 1894 } 1895 } 1896 } else { 1897 if (entry_def->children) { 1898 error = ParseEntry(value, entry_def, entry); 1899 } else if (sep_char == ':') { 1900 // Any value whose separator is a with a ':' means this value has a 1901 // string argument 1902 // that needs to be stored in the entry (like 1903 // "${script.var:modulename.function}") 1904 entry.string = value.str(); 1905 } else { 1906 error.SetErrorStringWithFormat( 1907 "'%s' followed by '%s' but it has no children", key.str().c_str(), 1908 value.str().c_str()); 1909 } 1910 } 1911 return error; 1912 } 1913 } 1914 StreamString error_strm; 1915 if (parent->type == FormatEntity::Entry::Type::Root) 1916 error_strm.Printf( 1917 "invalid top level item '%s'. Valid top level items are: ", 1918 key.str().c_str()); 1919 else 1920 error_strm.Printf("invalid member '%s' in '%s'. Valid members are: ", 1921 key.str().c_str(), parent->name); 1922 DumpCommaSeparatedChildEntryNames(error_strm, parent); 1923 error.SetErrorStringWithFormat("%s", error_strm.GetData()); 1924 return error; 1925 } 1926 1927 static const FormatEntity::Entry::Definition * 1928 FindEntry(const llvm::StringRef &format_str, 1929 const FormatEntity::Entry::Definition *parent, 1930 llvm::StringRef &remainder) { 1931 Error error; 1932 1933 std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.'); 1934 const size_t n = parent->num_children; 1935 for (size_t i = 0; i < n; ++i) { 1936 const FormatEntity::Entry::Definition *entry_def = parent->children + i; 1937 if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') { 1938 if (p.second.empty()) { 1939 if (format_str.back() == '.') 1940 remainder = format_str.drop_front(format_str.size() - 1); 1941 else 1942 remainder = llvm::StringRef(); // Exact match 1943 return entry_def; 1944 } else { 1945 if (entry_def->children) { 1946 return FindEntry(p.second, entry_def, remainder); 1947 } else { 1948 remainder = p.second; 1949 return entry_def; 1950 } 1951 } 1952 } 1953 } 1954 remainder = format_str; 1955 return parent; 1956 } 1957 1958 Error FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry, 1959 uint32_t depth) { 1960 Error error; 1961 while (!format.empty() && error.Success()) { 1962 const size_t non_special_chars = format.find_first_of("${}\\"); 1963 1964 if (non_special_chars == llvm::StringRef::npos) { 1965 // No special characters, just string bytes so add them and we are done 1966 parent_entry.AppendText(format); 1967 return error; 1968 } 1969 1970 if (non_special_chars > 0) { 1971 // We have a special character, so add all characters before these as a 1972 // plain string 1973 parent_entry.AppendText(format.substr(0, non_special_chars)); 1974 format = format.drop_front(non_special_chars); 1975 } 1976 1977 switch (format[0]) { 1978 case '\0': 1979 return error; 1980 1981 case '{': { 1982 format = format.drop_front(); // Skip the '{' 1983 Entry scope_entry(Entry::Type::Scope); 1984 error = FormatEntity::ParseInternal(format, scope_entry, depth + 1); 1985 if (error.Fail()) 1986 return error; 1987 parent_entry.AppendEntry(std::move(scope_entry)); 1988 } break; 1989 1990 case '}': 1991 if (depth == 0) 1992 error.SetErrorString("unmatched '}' character"); 1993 else 1994 format = 1995 format 1996 .drop_front(); // Skip the '}' as we are at the end of the scope 1997 return error; 1998 1999 case '\\': { 2000 format = format.drop_front(); // Skip the '\' character 2001 if (format.empty()) { 2002 error.SetErrorString( 2003 "'\\' character was not followed by another character"); 2004 return error; 2005 } 2006 2007 const char desens_char = format[0]; 2008 format = format.drop_front(); // Skip the desensitized char character 2009 switch (desens_char) { 2010 case 'a': 2011 parent_entry.AppendChar('\a'); 2012 break; 2013 case 'b': 2014 parent_entry.AppendChar('\b'); 2015 break; 2016 case 'f': 2017 parent_entry.AppendChar('\f'); 2018 break; 2019 case 'n': 2020 parent_entry.AppendChar('\n'); 2021 break; 2022 case 'r': 2023 parent_entry.AppendChar('\r'); 2024 break; 2025 case 't': 2026 parent_entry.AppendChar('\t'); 2027 break; 2028 case 'v': 2029 parent_entry.AppendChar('\v'); 2030 break; 2031 case '\'': 2032 parent_entry.AppendChar('\''); 2033 break; 2034 case '\\': 2035 parent_entry.AppendChar('\\'); 2036 break; 2037 case '0': 2038 // 1 to 3 octal chars 2039 { 2040 // Make a string that can hold onto the initial zero char, 2041 // up to 3 octal digits, and a terminating NULL. 2042 char oct_str[5] = {0, 0, 0, 0, 0}; 2043 2044 int i; 2045 for (i = 0; (format[i] >= '0' && format[i] <= '7') && i < 4; ++i) 2046 oct_str[i] = format[i]; 2047 2048 // We don't want to consume the last octal character since 2049 // the main for loop will do this for us, so we advance p by 2050 // one less than i (even if i is zero) 2051 format = format.drop_front(i); 2052 unsigned long octal_value = ::strtoul(oct_str, nullptr, 8); 2053 if (octal_value <= UINT8_MAX) { 2054 parent_entry.AppendChar((char)octal_value); 2055 } else { 2056 error.SetErrorString("octal number is larger than a single byte"); 2057 return error; 2058 } 2059 } 2060 break; 2061 2062 case 'x': 2063 // hex number in the format 2064 if (isxdigit(format[0])) { 2065 // Make a string that can hold onto two hex chars plus a 2066 // NULL terminator 2067 char hex_str[3] = {0, 0, 0}; 2068 hex_str[0] = format[0]; 2069 2070 format = format.drop_front(); 2071 2072 if (isxdigit(format[0])) { 2073 hex_str[1] = format[0]; 2074 format = format.drop_front(); 2075 } 2076 2077 unsigned long hex_value = strtoul(hex_str, nullptr, 16); 2078 if (hex_value <= UINT8_MAX) { 2079 parent_entry.AppendChar((char)hex_value); 2080 } else { 2081 error.SetErrorString("hex number is larger than a single byte"); 2082 return error; 2083 } 2084 } else { 2085 parent_entry.AppendChar(desens_char); 2086 } 2087 break; 2088 2089 default: 2090 // Just desensitize any other character by just printing what 2091 // came after the '\' 2092 parent_entry.AppendChar(desens_char); 2093 break; 2094 } 2095 } break; 2096 2097 case '$': 2098 if (format.size() == 1) { 2099 // '$' at the end of a format string, just print the '$' 2100 parent_entry.AppendText("$"); 2101 } else { 2102 format = format.drop_front(); // Skip the '$' 2103 2104 if (format[0] == '{') { 2105 format = format.drop_front(); // Skip the '{' 2106 2107 llvm::StringRef variable, variable_format; 2108 error = FormatEntity::ExtractVariableInfo(format, variable, 2109 variable_format); 2110 if (error.Fail()) 2111 return error; 2112 bool verify_is_thread_id = false; 2113 Entry entry; 2114 if (!variable_format.empty()) { 2115 entry.printf_format = variable_format.str(); 2116 2117 // If the format contains a '%' we are going to assume this is 2118 // a printf style format. So if you want to format your thread ID 2119 // using "0x%llx" you can use: 2120 // ${thread.id%0x%llx} 2121 // 2122 // If there is no '%' in the format, then it is assumed to be a 2123 // LLDB format name, or one of the extended formats specified in 2124 // the switch statement below. 2125 2126 if (entry.printf_format.find('%') == std::string::npos) { 2127 bool clear_printf = false; 2128 2129 if (FormatManager::GetFormatFromCString( 2130 entry.printf_format.c_str(), false, entry.fmt)) { 2131 // We have an LLDB format, so clear the printf format 2132 clear_printf = true; 2133 } else if (entry.printf_format.size() == 1) { 2134 switch (entry.printf_format[0]) { 2135 case '@': // if this is an @ sign, print ObjC description 2136 entry.number = ValueObject:: 2137 eValueObjectRepresentationStyleLanguageSpecific; 2138 clear_printf = true; 2139 break; 2140 case 'V': // if this is a V, print the value using the default 2141 // format 2142 entry.number = 2143 ValueObject::eValueObjectRepresentationStyleValue; 2144 clear_printf = true; 2145 break; 2146 case 'L': // if this is an L, print the location of the value 2147 entry.number = 2148 ValueObject::eValueObjectRepresentationStyleLocation; 2149 clear_printf = true; 2150 break; 2151 case 'S': // if this is an S, print the summary after all 2152 entry.number = 2153 ValueObject::eValueObjectRepresentationStyleSummary; 2154 clear_printf = true; 2155 break; 2156 case '#': // if this is a '#', print the number of children 2157 entry.number = 2158 ValueObject::eValueObjectRepresentationStyleChildrenCount; 2159 clear_printf = true; 2160 break; 2161 case 'T': // if this is a 'T', print the type 2162 entry.number = 2163 ValueObject::eValueObjectRepresentationStyleType; 2164 clear_printf = true; 2165 break; 2166 case 'N': // if this is a 'N', print the name 2167 entry.number = 2168 ValueObject::eValueObjectRepresentationStyleName; 2169 clear_printf = true; 2170 break; 2171 case '>': // if this is a '>', print the expression path 2172 entry.number = ValueObject:: 2173 eValueObjectRepresentationStyleExpressionPath; 2174 clear_printf = true; 2175 break; 2176 default: 2177 error.SetErrorStringWithFormat("invalid format: '%s'", 2178 entry.printf_format.c_str()); 2179 return error; 2180 } 2181 } else if (FormatManager::GetFormatFromCString( 2182 entry.printf_format.c_str(), true, entry.fmt)) { 2183 clear_printf = true; 2184 } else if (entry.printf_format == "tid") { 2185 verify_is_thread_id = true; 2186 } else { 2187 error.SetErrorStringWithFormat("invalid format: '%s'", 2188 entry.printf_format.c_str()); 2189 return error; 2190 } 2191 2192 // Our format string turned out to not be a printf style format 2193 // so lets clear the string 2194 if (clear_printf) 2195 entry.printf_format.clear(); 2196 } 2197 } 2198 2199 // Check for dereferences 2200 if (variable[0] == '*') { 2201 entry.deref = true; 2202 variable = variable.drop_front(); 2203 } 2204 2205 error = ParseEntry(variable, &g_root, entry); 2206 if (error.Fail()) 2207 return error; 2208 2209 if (verify_is_thread_id) { 2210 if (entry.type != Entry::Type::ThreadID && 2211 entry.type != Entry::Type::ThreadProtocolID) { 2212 error.SetErrorString("the 'tid' format can only be used on " 2213 "${thread.id} and ${thread.protocol_id}"); 2214 } 2215 } 2216 2217 switch (entry.type) { 2218 case Entry::Type::Variable: 2219 case Entry::Type::VariableSynthetic: 2220 if (entry.number == 0) { 2221 if (entry.string.empty()) 2222 entry.number = 2223 ValueObject::eValueObjectRepresentationStyleValue; 2224 else 2225 entry.number = 2226 ValueObject::eValueObjectRepresentationStyleSummary; 2227 } 2228 break; 2229 default: 2230 // Make sure someone didn't try to dereference anything but ${var} 2231 // or ${svar} 2232 if (entry.deref) { 2233 error.SetErrorStringWithFormat( 2234 "${%s} can't be dereferenced, only ${var} and ${svar} can.", 2235 variable.str().c_str()); 2236 return error; 2237 } 2238 } 2239 // Check if this entry just wants to insert a constant string 2240 // value into the parent_entry, if so, insert the string with 2241 // AppendText, else append the entry to the parent_entry. 2242 if (entry.type == Entry::Type::InsertString) 2243 parent_entry.AppendText(entry.string.c_str()); 2244 else 2245 parent_entry.AppendEntry(std::move(entry)); 2246 } 2247 } 2248 break; 2249 } 2250 } 2251 return error; 2252 } 2253 2254 Error FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str, 2255 llvm::StringRef &variable_name, 2256 llvm::StringRef &variable_format) { 2257 Error error; 2258 variable_name = llvm::StringRef(); 2259 variable_format = llvm::StringRef(); 2260 2261 const size_t paren_pos = format_str.find('}'); 2262 if (paren_pos != llvm::StringRef::npos) { 2263 const size_t percent_pos = format_str.find('%'); 2264 if (percent_pos < paren_pos) { 2265 if (percent_pos > 0) { 2266 if (percent_pos > 1) 2267 variable_name = format_str.substr(0, percent_pos); 2268 variable_format = 2269 format_str.substr(percent_pos + 1, paren_pos - (percent_pos + 1)); 2270 } 2271 } else { 2272 variable_name = format_str.substr(0, paren_pos); 2273 } 2274 // Strip off elements and the formatting and the trailing '}' 2275 format_str = format_str.substr(paren_pos + 1); 2276 } else { 2277 error.SetErrorStringWithFormat( 2278 "missing terminating '}' character for '${%s'", 2279 format_str.str().c_str()); 2280 } 2281 return error; 2282 } 2283 2284 bool FormatEntity::FormatFileSpec(const FileSpec &file_spec, Stream &s, 2285 llvm::StringRef variable_name, 2286 llvm::StringRef variable_format) { 2287 if (variable_name.empty() || variable_name.equals(".fullpath")) { 2288 file_spec.Dump(&s); 2289 return true; 2290 } else if (variable_name.equals(".basename")) { 2291 s.PutCString(file_spec.GetFilename().AsCString("")); 2292 return true; 2293 } else if (variable_name.equals(".dirname")) { 2294 s.PutCString(file_spec.GetFilename().AsCString("")); 2295 return true; 2296 } 2297 return false; 2298 } 2299 2300 static std::string MakeMatch(const llvm::StringRef &prefix, 2301 const char *suffix) { 2302 std::string match(prefix.str()); 2303 match.append(suffix); 2304 return match; 2305 } 2306 2307 static void AddMatches(const FormatEntity::Entry::Definition *def, 2308 const llvm::StringRef &prefix, 2309 const llvm::StringRef &match_prefix, 2310 StringList &matches) { 2311 const size_t n = def->num_children; 2312 if (n > 0) { 2313 for (size_t i = 0; i < n; ++i) { 2314 std::string match = prefix.str(); 2315 if (match_prefix.empty()) 2316 matches.AppendString(MakeMatch(prefix, def->children[i].name)); 2317 else if (strncmp(def->children[i].name, match_prefix.data(), 2318 match_prefix.size()) == 0) 2319 matches.AppendString( 2320 MakeMatch(prefix, def->children[i].name + match_prefix.size())); 2321 } 2322 } 2323 } 2324 2325 size_t FormatEntity::AutoComplete(llvm::StringRef str, int match_start_point, 2326 int max_return_elements, bool &word_complete, 2327 StringList &matches) { 2328 word_complete = false; 2329 str = str.drop_front(match_start_point); 2330 matches.Clear(); 2331 2332 const size_t dollar_pos = str.rfind('$'); 2333 if (dollar_pos == llvm::StringRef::npos) 2334 return 0; 2335 2336 // Hitting TAB after $ at the end of the string add a "{" 2337 if (dollar_pos == str.size() - 1) { 2338 std::string match = str.str(); 2339 match.append("{"); 2340 matches.AppendString(match); 2341 return 1; 2342 } 2343 2344 if (str[dollar_pos + 1] != '{') 2345 return 0; 2346 2347 const size_t close_pos = str.find('}', dollar_pos + 2); 2348 if (close_pos != llvm::StringRef::npos) 2349 return 0; 2350 2351 const size_t format_pos = str.find('%', dollar_pos + 2); 2352 if (format_pos != llvm::StringRef::npos) 2353 return 0; 2354 2355 llvm::StringRef partial_variable(str.substr(dollar_pos + 2)); 2356 if (partial_variable.empty()) { 2357 // Suggest all top level entites as we are just past "${" 2358 AddMatches(&g_root, str, llvm::StringRef(), matches); 2359 return matches.GetSize(); 2360 } 2361 2362 // We have a partially specified variable, find it 2363 llvm::StringRef remainder; 2364 const FormatEntity::Entry::Definition *entry_def = 2365 FindEntry(partial_variable, &g_root, remainder); 2366 if (!entry_def) 2367 return 0; 2368 2369 const size_t n = entry_def->num_children; 2370 2371 if (remainder.empty()) { 2372 // Exact match 2373 if (n > 0) { 2374 // "${thread.info" <TAB> 2375 matches.AppendString(MakeMatch(str, ".")); 2376 } else { 2377 // "${thread.id" <TAB> 2378 matches.AppendString(MakeMatch(str, "}")); 2379 word_complete = true; 2380 } 2381 } else if (remainder.equals(".")) { 2382 // "${thread." <TAB> 2383 AddMatches(entry_def, str, llvm::StringRef(), matches); 2384 } else { 2385 // We have a partial match 2386 // "${thre" <TAB> 2387 AddMatches(entry_def, str, remainder, matches); 2388 } 2389 return matches.GetSize(); 2390 } 2391