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/Host/FileSpec.h" 29 #include "lldb/Interpreter/CommandInterpreter.h" 30 #include "lldb/Symbol/Block.h" 31 #include "lldb/Symbol/CompileUnit.h" 32 #include "lldb/Symbol/Function.h" 33 #include "lldb/Symbol/LineEntry.h" 34 #include "lldb/Symbol/Symbol.h" 35 #include "lldb/Symbol/VariableList.h" 36 #include "lldb/Target/ExecutionContext.h" 37 #include "lldb/Target/Language.h" 38 #include "lldb/Target/Process.h" 39 #include "lldb/Target/RegisterContext.h" 40 #include "lldb/Target/SectionLoadList.h" 41 #include "lldb/Target/StackFrame.h" 42 #include "lldb/Target/StopInfo.h" 43 #include "lldb/Target/Target.h" 44 #include "lldb/Target/Thread.h" 45 #include "lldb/Utility/AnsiTerminal.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, 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 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 format = "%" PRIu64; 1192 } 1193 } else { 1194 format = entry.printf_format.c_str(); 1195 } 1196 } 1197 s.Printf(format, thread->GetID()); 1198 return true; 1199 } 1200 } 1201 return false; 1202 1203 case Entry::Type::ThreadProtocolID: 1204 if (exe_ctx) { 1205 Thread *thread = exe_ctx->GetThreadPtr(); 1206 if (thread) { 1207 const char *format = "0x%4.4" PRIx64; 1208 if (!entry.printf_format.empty()) 1209 format = entry.printf_format.c_str(); 1210 s.Printf(format, thread->GetProtocolID()); 1211 return true; 1212 } 1213 } 1214 return false; 1215 1216 case Entry::Type::ThreadIndexID: 1217 if (exe_ctx) { 1218 Thread *thread = exe_ctx->GetThreadPtr(); 1219 if (thread) { 1220 const char *format = "%" PRIu32; 1221 if (!entry.printf_format.empty()) 1222 format = entry.printf_format.c_str(); 1223 s.Printf(format, thread->GetIndexID()); 1224 return true; 1225 } 1226 } 1227 return false; 1228 1229 case Entry::Type::ThreadName: 1230 if (exe_ctx) { 1231 Thread *thread = exe_ctx->GetThreadPtr(); 1232 if (thread) { 1233 const char *cstr = thread->GetName(); 1234 if (cstr && cstr[0]) { 1235 s.PutCString(cstr); 1236 return true; 1237 } 1238 } 1239 } 1240 return false; 1241 1242 case Entry::Type::ThreadQueue: 1243 if (exe_ctx) { 1244 Thread *thread = exe_ctx->GetThreadPtr(); 1245 if (thread) { 1246 const char *cstr = thread->GetQueueName(); 1247 if (cstr && cstr[0]) { 1248 s.PutCString(cstr); 1249 return true; 1250 } 1251 } 1252 } 1253 return false; 1254 1255 case Entry::Type::ThreadStopReason: 1256 if (exe_ctx) { 1257 Thread *thread = exe_ctx->GetThreadPtr(); 1258 if (thread) { 1259 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1260 if (stop_info_sp && stop_info_sp->IsValid()) { 1261 const char *cstr = stop_info_sp->GetDescription(); 1262 if (cstr && cstr[0]) { 1263 s.PutCString(cstr); 1264 return true; 1265 } 1266 } 1267 } 1268 } 1269 return false; 1270 1271 case Entry::Type::ThreadReturnValue: 1272 if (exe_ctx) { 1273 Thread *thread = exe_ctx->GetThreadPtr(); 1274 if (thread) { 1275 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1276 if (stop_info_sp && stop_info_sp->IsValid()) { 1277 ValueObjectSP return_valobj_sp = 1278 StopInfo::GetReturnValueObject(stop_info_sp); 1279 if (return_valobj_sp) { 1280 return_valobj_sp->Dump(s); 1281 return true; 1282 } 1283 } 1284 } 1285 } 1286 return false; 1287 1288 case Entry::Type::ThreadCompletedExpression: 1289 if (exe_ctx) { 1290 Thread *thread = exe_ctx->GetThreadPtr(); 1291 if (thread) { 1292 StopInfoSP stop_info_sp = thread->GetStopInfo(); 1293 if (stop_info_sp && stop_info_sp->IsValid()) { 1294 ExpressionVariableSP expression_var_sp = 1295 StopInfo::GetExpressionVariable(stop_info_sp); 1296 if (expression_var_sp && expression_var_sp->GetValueObject()) { 1297 expression_var_sp->GetValueObject()->Dump(s); 1298 return true; 1299 } 1300 } 1301 } 1302 } 1303 return false; 1304 1305 case Entry::Type::ScriptThread: 1306 if (exe_ctx) { 1307 Thread *thread = exe_ctx->GetThreadPtr(); 1308 if (thread) 1309 return RunScriptFormatKeyword(s, sc, exe_ctx, thread, 1310 entry.string.c_str()); 1311 } 1312 return false; 1313 1314 case Entry::Type::ThreadInfo: 1315 if (exe_ctx) { 1316 Thread *thread = exe_ctx->GetThreadPtr(); 1317 if (thread) { 1318 StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); 1319 if (object_sp && 1320 object_sp->GetType() == StructuredData::Type::eTypeDictionary) { 1321 if (FormatThreadExtendedInfoRecurse(entry, object_sp, sc, exe_ctx, s)) 1322 return true; 1323 } 1324 } 1325 } 1326 return false; 1327 1328 case Entry::Type::TargetArch: 1329 if (exe_ctx) { 1330 Target *target = exe_ctx->GetTargetPtr(); 1331 if (target) { 1332 const ArchSpec &arch = target->GetArchitecture(); 1333 if (arch.IsValid()) { 1334 s.PutCString(arch.GetArchitectureName()); 1335 return true; 1336 } 1337 } 1338 } 1339 return false; 1340 1341 case Entry::Type::ScriptTarget: 1342 if (exe_ctx) { 1343 Target *target = exe_ctx->GetTargetPtr(); 1344 if (target) 1345 return RunScriptFormatKeyword(s, sc, exe_ctx, target, 1346 entry.string.c_str()); 1347 } 1348 return false; 1349 1350 case Entry::Type::ModuleFile: 1351 if (sc) { 1352 Module *module = sc->module_sp.get(); 1353 if (module) { 1354 if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number)) 1355 return true; 1356 } 1357 } 1358 return false; 1359 1360 case Entry::Type::File: 1361 if (sc) { 1362 CompileUnit *cu = sc->comp_unit; 1363 if (cu) { 1364 // CompileUnit is a FileSpec 1365 if (DumpFile(s, *cu, (FileKind)entry.number)) 1366 return true; 1367 } 1368 } 1369 return false; 1370 1371 case Entry::Type::Lang: 1372 if (sc) { 1373 CompileUnit *cu = sc->comp_unit; 1374 if (cu) { 1375 const char *lang_name = 1376 Language::GetNameForLanguageType(cu->GetLanguage()); 1377 if (lang_name) { 1378 s.PutCString(lang_name); 1379 return true; 1380 } 1381 } 1382 } 1383 return false; 1384 1385 case Entry::Type::FrameIndex: 1386 if (exe_ctx) { 1387 StackFrame *frame = exe_ctx->GetFramePtr(); 1388 if (frame) { 1389 const char *format = "%" PRIu32; 1390 if (!entry.printf_format.empty()) 1391 format = entry.printf_format.c_str(); 1392 s.Printf(format, frame->GetFrameIndex()); 1393 return true; 1394 } 1395 } 1396 return false; 1397 1398 case Entry::Type::FrameRegisterPC: 1399 if (exe_ctx) { 1400 StackFrame *frame = exe_ctx->GetFramePtr(); 1401 if (frame) { 1402 const Address &pc_addr = frame->GetFrameCodeAddress(); 1403 if (pc_addr.IsValid()) { 1404 if (DumpAddress(s, sc, exe_ctx, pc_addr, false)) 1405 return true; 1406 } 1407 } 1408 } 1409 return false; 1410 1411 case Entry::Type::FrameRegisterSP: 1412 if (exe_ctx) { 1413 StackFrame *frame = exe_ctx->GetFramePtr(); 1414 if (frame) { 1415 if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 1416 (lldb::Format)entry.number)) 1417 return true; 1418 } 1419 } 1420 return false; 1421 1422 case Entry::Type::FrameRegisterFP: 1423 if (exe_ctx) { 1424 StackFrame *frame = exe_ctx->GetFramePtr(); 1425 if (frame) { 1426 if (DumpRegister(s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, 1427 (lldb::Format)entry.number)) 1428 return true; 1429 } 1430 } 1431 return false; 1432 1433 case Entry::Type::FrameRegisterFlags: 1434 if (exe_ctx) { 1435 StackFrame *frame = exe_ctx->GetFramePtr(); 1436 if (frame) { 1437 if (DumpRegister(s, frame, eRegisterKindGeneric, 1438 LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number)) 1439 return true; 1440 } 1441 } 1442 return false; 1443 1444 case Entry::Type::FrameNoDebug: 1445 if (exe_ctx) { 1446 StackFrame *frame = exe_ctx->GetFramePtr(); 1447 if (frame) { 1448 return !frame->HasDebugInformation(); 1449 } 1450 } 1451 return true; 1452 1453 case Entry::Type::FrameRegisterByName: 1454 if (exe_ctx) { 1455 StackFrame *frame = exe_ctx->GetFramePtr(); 1456 if (frame) { 1457 if (DumpRegister(s, frame, entry.string.c_str(), 1458 (lldb::Format)entry.number)) 1459 return true; 1460 } 1461 } 1462 return false; 1463 1464 case Entry::Type::ScriptFrame: 1465 if (exe_ctx) { 1466 StackFrame *frame = exe_ctx->GetFramePtr(); 1467 if (frame) 1468 return RunScriptFormatKeyword(s, sc, exe_ctx, frame, 1469 entry.string.c_str()); 1470 } 1471 return false; 1472 1473 case Entry::Type::FunctionID: 1474 if (sc) { 1475 if (sc->function) { 1476 s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); 1477 return true; 1478 } else if (sc->symbol) { 1479 s.Printf("symbol[%u]", sc->symbol->GetID()); 1480 return true; 1481 } 1482 } 1483 return false; 1484 1485 case Entry::Type::FunctionDidChange: 1486 return function_changed; 1487 1488 case Entry::Type::FunctionInitialFunction: 1489 return initial_function; 1490 1491 case Entry::Type::FunctionName: { 1492 Language *language_plugin = nullptr; 1493 bool language_plugin_handled = false; 1494 StreamString ss; 1495 if (sc->function) 1496 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1497 else if (sc->symbol) 1498 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1499 if (language_plugin) { 1500 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1501 sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss); 1502 } 1503 if (language_plugin_handled) { 1504 s << ss.GetString(); 1505 return true; 1506 } else { 1507 const char *name = nullptr; 1508 if (sc->function) 1509 name = sc->function->GetName().AsCString(nullptr); 1510 else if (sc->symbol) 1511 name = sc->symbol->GetName().AsCString(nullptr); 1512 if (name) { 1513 s.PutCString(name); 1514 1515 if (sc->block) { 1516 Block *inline_block = sc->block->GetContainingInlinedBlock(); 1517 if (inline_block) { 1518 const InlineFunctionInfo *inline_info = 1519 sc->block->GetInlinedFunctionInfo(); 1520 if (inline_info) { 1521 s.PutCString(" [inlined] "); 1522 inline_info->GetName(sc->function->GetLanguage()).Dump(&s); 1523 } 1524 } 1525 } 1526 return true; 1527 } 1528 } 1529 } 1530 return false; 1531 1532 case Entry::Type::FunctionNameNoArgs: { 1533 Language *language_plugin = nullptr; 1534 bool language_plugin_handled = false; 1535 StreamString ss; 1536 if (sc->function) 1537 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1538 else if (sc->symbol) 1539 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1540 if (language_plugin) { 1541 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1542 sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs, 1543 ss); 1544 } 1545 if (language_plugin_handled) { 1546 s << ss.GetString(); 1547 return true; 1548 } else { 1549 ConstString name; 1550 if (sc->function) 1551 name = sc->function->GetNameNoArguments(); 1552 else if (sc->symbol) 1553 name = sc->symbol->GetNameNoArguments(); 1554 if (name) { 1555 s.PutCString(name.GetCString()); 1556 return true; 1557 } 1558 } 1559 } 1560 return false; 1561 1562 case Entry::Type::FunctionNameWithArgs: { 1563 Language *language_plugin = nullptr; 1564 bool language_plugin_handled = false; 1565 StreamString ss; 1566 if (sc->function) 1567 language_plugin = Language::FindPlugin(sc->function->GetLanguage()); 1568 else if (sc->symbol) 1569 language_plugin = Language::FindPlugin(sc->symbol->GetLanguage()); 1570 if (language_plugin) { 1571 language_plugin_handled = language_plugin->GetFunctionDisplayName( 1572 sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithArgs, ss); 1573 } 1574 if (language_plugin_handled) { 1575 s << ss.GetString(); 1576 return true; 1577 } else { 1578 // Print the function name with arguments in it 1579 if (sc->function) { 1580 ExecutionContextScope *exe_scope = 1581 exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; 1582 const char *cstr = sc->function->GetName().AsCString(nullptr); 1583 if (cstr) { 1584 const InlineFunctionInfo *inline_info = nullptr; 1585 VariableListSP variable_list_sp; 1586 bool get_function_vars = true; 1587 if (sc->block) { 1588 Block *inline_block = sc->block->GetContainingInlinedBlock(); 1589 1590 if (inline_block) { 1591 get_function_vars = false; 1592 inline_info = sc->block->GetInlinedFunctionInfo(); 1593 if (inline_info) 1594 variable_list_sp = inline_block->GetBlockVariableList(true); 1595 } 1596 } 1597 1598 if (get_function_vars) { 1599 variable_list_sp = 1600 sc->function->GetBlock(true).GetBlockVariableList(true); 1601 } 1602 1603 if (inline_info) { 1604 s.PutCString(cstr); 1605 s.PutCString(" [inlined] "); 1606 cstr = 1607 inline_info->GetName(sc->function->GetLanguage()).GetCString(); 1608 } 1609 1610 VariableList args; 1611 if (variable_list_sp) 1612 variable_list_sp->AppendVariablesWithScope( 1613 eValueTypeVariableArgument, args); 1614 if (args.GetSize() > 0) { 1615 const char *open_paren = strchr(cstr, '('); 1616 const char *close_paren = nullptr; 1617 const char *generic = strchr(cstr, '<'); 1618 // if before the arguments list begins there is a template sign 1619 // then scan to the end of the generic args before you try to find 1620 // the arguments list 1621 if (generic && open_paren && generic < open_paren) { 1622 int generic_depth = 1; 1623 ++generic; 1624 for (; *generic && generic_depth > 0; generic++) { 1625 if (*generic == '<') 1626 generic_depth++; 1627 if (*generic == '>') 1628 generic_depth--; 1629 } 1630 if (*generic) 1631 open_paren = strchr(generic, '('); 1632 else 1633 open_paren = nullptr; 1634 } 1635 if (open_paren) { 1636 if (IsToken(open_paren, "(anonymous namespace)")) { 1637 open_paren = 1638 strchr(open_paren + strlen("(anonymous namespace)"), '('); 1639 if (open_paren) 1640 close_paren = strchr(open_paren, ')'); 1641 } else 1642 close_paren = strchr(open_paren, ')'); 1643 } 1644 1645 if (open_paren) 1646 s.Write(cstr, open_paren - cstr + 1); 1647 else { 1648 s.PutCString(cstr); 1649 s.PutChar('('); 1650 } 1651 const size_t num_args = args.GetSize(); 1652 for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) { 1653 std::string buffer; 1654 1655 VariableSP var_sp(args.GetVariableAtIndex(arg_idx)); 1656 ValueObjectSP var_value_sp( 1657 ValueObjectVariable::Create(exe_scope, var_sp)); 1658 StreamString ss; 1659 llvm::StringRef var_representation; 1660 const char *var_name = var_value_sp->GetName().GetCString(); 1661 if (var_value_sp->GetCompilerType().IsValid()) { 1662 if (var_value_sp && exe_scope->CalculateTarget()) 1663 var_value_sp = 1664 var_value_sp->GetQualifiedRepresentationIfAvailable( 1665 exe_scope->CalculateTarget() 1666 ->TargetProperties::GetPreferDynamicValue(), 1667 exe_scope->CalculateTarget() 1668 ->TargetProperties::GetEnableSyntheticValue()); 1669 if (var_value_sp->GetCompilerType().IsAggregateType() && 1670 DataVisualization::ShouldPrintAsOneLiner(*var_value_sp)) { 1671 static StringSummaryFormat format( 1672 TypeSummaryImpl::Flags() 1673 .SetHideItemNames(false) 1674 .SetShowMembersOneLiner(true), 1675 ""); 1676 format.FormatObject(var_value_sp.get(), buffer, 1677 TypeSummaryOptions()); 1678 var_representation = buffer; 1679 } else 1680 var_value_sp->DumpPrintableRepresentation( 1681 ss, ValueObject::ValueObjectRepresentationStyle:: 1682 eValueObjectRepresentationStyleSummary, 1683 eFormatDefault, 1684 ValueObject::PrintableRepresentationSpecialCases::eAllow, 1685 false); 1686 } 1687 1688 if (!ss.GetString().empty()) 1689 var_representation = ss.GetString(); 1690 if (arg_idx > 0) 1691 s.PutCString(", "); 1692 if (var_value_sp->GetError().Success()) { 1693 if (!var_representation.empty()) 1694 s.Printf("%s=%s", var_name, var_representation.str().c_str()); 1695 else 1696 s.Printf("%s=%s at %s", var_name, 1697 var_value_sp->GetTypeName().GetCString(), 1698 var_value_sp->GetLocationAsCString()); 1699 } else 1700 s.Printf("%s=<unavailable>", var_name); 1701 } 1702 1703 if (close_paren) 1704 s.PutCString(close_paren); 1705 else 1706 s.PutChar(')'); 1707 1708 } else { 1709 s.PutCString(cstr); 1710 } 1711 return true; 1712 } 1713 } else if (sc->symbol) { 1714 const char *cstr = sc->symbol->GetName().AsCString(nullptr); 1715 if (cstr) { 1716 s.PutCString(cstr); 1717 return true; 1718 } 1719 } 1720 } 1721 } 1722 return false; 1723 1724 case Entry::Type::FunctionAddrOffset: 1725 if (addr) { 1726 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, false, false, 1727 false)) 1728 return true; 1729 } 1730 return false; 1731 1732 case Entry::Type::FunctionAddrOffsetConcrete: 1733 if (addr) { 1734 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, *addr, true, true, 1735 true)) 1736 return true; 1737 } 1738 return false; 1739 1740 case Entry::Type::FunctionLineOffset: 1741 return (DumpAddressOffsetFromFunction(s, sc, exe_ctx, 1742 sc->line_entry.range.GetBaseAddress(), 1743 false, false, false)); 1744 1745 case Entry::Type::FunctionPCOffset: 1746 if (exe_ctx) { 1747 StackFrame *frame = exe_ctx->GetFramePtr(); 1748 if (frame) { 1749 if (DumpAddressOffsetFromFunction(s, sc, exe_ctx, 1750 frame->GetFrameCodeAddress(), false, 1751 false, false)) 1752 return true; 1753 } 1754 } 1755 return false; 1756 1757 case Entry::Type::FunctionChanged: 1758 return function_changed; 1759 1760 case Entry::Type::FunctionIsOptimized: { 1761 bool is_optimized = false; 1762 if (sc->function && sc->function->GetIsOptimized()) { 1763 is_optimized = true; 1764 } 1765 return is_optimized; 1766 } 1767 1768 case Entry::Type::FunctionInitial: 1769 return initial_function; 1770 1771 case Entry::Type::LineEntryFile: 1772 if (sc && sc->line_entry.IsValid()) { 1773 Module *module = sc->module_sp.get(); 1774 if (module) { 1775 if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number)) 1776 return true; 1777 } 1778 } 1779 return false; 1780 1781 case Entry::Type::LineEntryLineNumber: 1782 if (sc && sc->line_entry.IsValid()) { 1783 const char *format = "%" PRIu32; 1784 if (!entry.printf_format.empty()) 1785 format = entry.printf_format.c_str(); 1786 s.Printf(format, sc->line_entry.line); 1787 return true; 1788 } 1789 return false; 1790 1791 case Entry::Type::LineEntryStartAddress: 1792 case Entry::Type::LineEntryEndAddress: 1793 if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) { 1794 Address addr = sc->line_entry.range.GetBaseAddress(); 1795 1796 if (entry.type == Entry::Type::LineEntryEndAddress) 1797 addr.Slide(sc->line_entry.range.GetByteSize()); 1798 if (DumpAddress(s, sc, exe_ctx, addr, false)) 1799 return true; 1800 } 1801 return false; 1802 1803 case Entry::Type::CurrentPCArrow: 1804 if (addr && exe_ctx && exe_ctx->GetFramePtr()) { 1805 RegisterContextSP reg_ctx = 1806 exe_ctx->GetFramePtr()->GetRegisterContextSP(); 1807 if (reg_ctx) { 1808 addr_t pc_loadaddr = reg_ctx->GetPC(); 1809 if (pc_loadaddr != LLDB_INVALID_ADDRESS) { 1810 Address pc; 1811 pc.SetLoadAddress(pc_loadaddr, exe_ctx->GetTargetPtr()); 1812 if (pc == *addr) { 1813 s.Printf("-> "); 1814 return true; 1815 } 1816 } 1817 } 1818 s.Printf(" "); 1819 return true; 1820 } 1821 return false; 1822 } 1823 return false; 1824 } 1825 1826 static bool DumpCommaSeparatedChildEntryNames( 1827 Stream &s, const FormatEntity::Entry::Definition *parent) { 1828 if (parent->children) { 1829 const size_t n = parent->num_children; 1830 for (size_t i = 0; i < n; ++i) { 1831 if (i > 0) 1832 s.PutCString(", "); 1833 s.Printf("\"%s\"", parent->children[i].name); 1834 } 1835 return true; 1836 } 1837 return false; 1838 } 1839 1840 static Error ParseEntry(const llvm::StringRef &format_str, 1841 const FormatEntity::Entry::Definition *parent, 1842 FormatEntity::Entry &entry) { 1843 Error error; 1844 1845 const size_t sep_pos = format_str.find_first_of(".[:"); 1846 const char sep_char = 1847 (sep_pos == llvm::StringRef::npos) ? '\0' : format_str[sep_pos]; 1848 llvm::StringRef key = format_str.substr(0, sep_pos); 1849 1850 const size_t n = parent->num_children; 1851 for (size_t i = 0; i < n; ++i) { 1852 const FormatEntity::Entry::Definition *entry_def = parent->children + i; 1853 if (key.equals(entry_def->name) || entry_def->name[0] == '*') { 1854 llvm::StringRef value; 1855 if (sep_char) 1856 value = 1857 format_str.substr(sep_pos + (entry_def->keep_separator ? 0 : 1)); 1858 switch (entry_def->type) { 1859 case FormatEntity::Entry::Type::ParentString: 1860 entry.string = format_str.str(); 1861 return error; // Success 1862 1863 case FormatEntity::Entry::Type::ParentNumber: 1864 entry.number = entry_def->data; 1865 return error; // Success 1866 1867 case FormatEntity::Entry::Type::InsertString: 1868 entry.type = entry_def->type; 1869 entry.string = entry_def->string; 1870 return error; // Success 1871 1872 default: 1873 entry.type = entry_def->type; 1874 break; 1875 } 1876 1877 if (value.empty()) { 1878 if (entry_def->type == FormatEntity::Entry::Type::Invalid) { 1879 if (entry_def->children) { 1880 StreamString error_strm; 1881 error_strm.Printf("'%s' can't be specified on its own, you must " 1882 "access one of its children: ", 1883 entry_def->name); 1884 DumpCommaSeparatedChildEntryNames(error_strm, entry_def); 1885 error.SetErrorStringWithFormat("%s", error_strm.GetData()); 1886 } else if (sep_char == ':') { 1887 // Any value whose separator is a with a ':' means this value has a 1888 // string argument 1889 // that needs to be stored in the entry (like "${script.var:}"). 1890 // In this case the string value is the empty string which is ok. 1891 } else { 1892 error.SetErrorStringWithFormat("%s", "invalid entry definitions"); 1893 } 1894 } 1895 } else { 1896 if (entry_def->children) { 1897 error = ParseEntry(value, entry_def, entry); 1898 } else if (sep_char == ':') { 1899 // Any value whose separator is a with a ':' means this value has a 1900 // string argument 1901 // that needs to be stored in the entry (like 1902 // "${script.var:modulename.function}") 1903 entry.string = value.str(); 1904 } else { 1905 error.SetErrorStringWithFormat( 1906 "'%s' followed by '%s' but it has no children", key.str().c_str(), 1907 value.str().c_str()); 1908 } 1909 } 1910 return error; 1911 } 1912 } 1913 StreamString error_strm; 1914 if (parent->type == FormatEntity::Entry::Type::Root) 1915 error_strm.Printf( 1916 "invalid top level item '%s'. Valid top level items are: ", 1917 key.str().c_str()); 1918 else 1919 error_strm.Printf("invalid member '%s' in '%s'. Valid members are: ", 1920 key.str().c_str(), parent->name); 1921 DumpCommaSeparatedChildEntryNames(error_strm, parent); 1922 error.SetErrorStringWithFormat("%s", error_strm.GetData()); 1923 return error; 1924 } 1925 1926 static const FormatEntity::Entry::Definition * 1927 FindEntry(const llvm::StringRef &format_str, 1928 const FormatEntity::Entry::Definition *parent, 1929 llvm::StringRef &remainder) { 1930 Error error; 1931 1932 std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.'); 1933 const size_t n = parent->num_children; 1934 for (size_t i = 0; i < n; ++i) { 1935 const FormatEntity::Entry::Definition *entry_def = parent->children + i; 1936 if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') { 1937 if (p.second.empty()) { 1938 if (format_str.back() == '.') 1939 remainder = format_str.drop_front(format_str.size() - 1); 1940 else 1941 remainder = llvm::StringRef(); // Exact match 1942 return entry_def; 1943 } else { 1944 if (entry_def->children) { 1945 return FindEntry(p.second, entry_def, remainder); 1946 } else { 1947 remainder = p.second; 1948 return entry_def; 1949 } 1950 } 1951 } 1952 } 1953 remainder = format_str; 1954 return parent; 1955 } 1956 1957 Error FormatEntity::ParseInternal(llvm::StringRef &format, Entry &parent_entry, 1958 uint32_t depth) { 1959 Error error; 1960 while (!format.empty() && error.Success()) { 1961 const size_t non_special_chars = format.find_first_of("${}\\"); 1962 1963 if (non_special_chars == llvm::StringRef::npos) { 1964 // No special characters, just string bytes so add them and we are done 1965 parent_entry.AppendText(format); 1966 return error; 1967 } 1968 1969 if (non_special_chars > 0) { 1970 // We have a special character, so add all characters before these as a 1971 // plain string 1972 parent_entry.AppendText(format.substr(0, non_special_chars)); 1973 format = format.drop_front(non_special_chars); 1974 } 1975 1976 switch (format[0]) { 1977 case '\0': 1978 return error; 1979 1980 case '{': { 1981 format = format.drop_front(); // Skip the '{' 1982 Entry scope_entry(Entry::Type::Scope); 1983 error = FormatEntity::ParseInternal(format, scope_entry, depth + 1); 1984 if (error.Fail()) 1985 return error; 1986 parent_entry.AppendEntry(std::move(scope_entry)); 1987 } break; 1988 1989 case '}': 1990 if (depth == 0) 1991 error.SetErrorString("unmatched '}' character"); 1992 else 1993 format = 1994 format 1995 .drop_front(); // Skip the '}' as we are at the end of the scope 1996 return error; 1997 1998 case '\\': { 1999 format = format.drop_front(); // Skip the '\' character 2000 if (format.empty()) { 2001 error.SetErrorString( 2002 "'\\' character was not followed by another character"); 2003 return error; 2004 } 2005 2006 const char desens_char = format[0]; 2007 format = format.drop_front(); // Skip the desensitized char character 2008 switch (desens_char) { 2009 case 'a': 2010 parent_entry.AppendChar('\a'); 2011 break; 2012 case 'b': 2013 parent_entry.AppendChar('\b'); 2014 break; 2015 case 'f': 2016 parent_entry.AppendChar('\f'); 2017 break; 2018 case 'n': 2019 parent_entry.AppendChar('\n'); 2020 break; 2021 case 'r': 2022 parent_entry.AppendChar('\r'); 2023 break; 2024 case 't': 2025 parent_entry.AppendChar('\t'); 2026 break; 2027 case 'v': 2028 parent_entry.AppendChar('\v'); 2029 break; 2030 case '\'': 2031 parent_entry.AppendChar('\''); 2032 break; 2033 case '\\': 2034 parent_entry.AppendChar('\\'); 2035 break; 2036 case '0': 2037 // 1 to 3 octal chars 2038 { 2039 // Make a string that can hold onto the initial zero char, 2040 // up to 3 octal digits, and a terminating NULL. 2041 char oct_str[5] = {0, 0, 0, 0, 0}; 2042 2043 int i; 2044 for (i = 0; (format[i] >= '0' && format[i] <= '7') && i < 4; ++i) 2045 oct_str[i] = format[i]; 2046 2047 // We don't want to consume the last octal character since 2048 // the main for loop will do this for us, so we advance p by 2049 // one less than i (even if i is zero) 2050 format = format.drop_front(i); 2051 unsigned long octal_value = ::strtoul(oct_str, nullptr, 8); 2052 if (octal_value <= UINT8_MAX) { 2053 parent_entry.AppendChar((char)octal_value); 2054 } else { 2055 error.SetErrorString("octal number is larger than a single byte"); 2056 return error; 2057 } 2058 } 2059 break; 2060 2061 case 'x': 2062 // hex number in the format 2063 if (isxdigit(format[0])) { 2064 // Make a string that can hold onto two hex chars plus a 2065 // NULL terminator 2066 char hex_str[3] = {0, 0, 0}; 2067 hex_str[0] = format[0]; 2068 2069 format = format.drop_front(); 2070 2071 if (isxdigit(format[0])) { 2072 hex_str[1] = format[0]; 2073 format = format.drop_front(); 2074 } 2075 2076 unsigned long hex_value = strtoul(hex_str, nullptr, 16); 2077 if (hex_value <= UINT8_MAX) { 2078 parent_entry.AppendChar((char)hex_value); 2079 } else { 2080 error.SetErrorString("hex number is larger than a single byte"); 2081 return error; 2082 } 2083 } else { 2084 parent_entry.AppendChar(desens_char); 2085 } 2086 break; 2087 2088 default: 2089 // Just desensitize any other character by just printing what 2090 // came after the '\' 2091 parent_entry.AppendChar(desens_char); 2092 break; 2093 } 2094 } break; 2095 2096 case '$': 2097 if (format.size() == 1) { 2098 // '$' at the end of a format string, just print the '$' 2099 parent_entry.AppendText("$"); 2100 } else { 2101 format = format.drop_front(); // Skip the '$' 2102 2103 if (format[0] == '{') { 2104 format = format.drop_front(); // Skip the '{' 2105 2106 llvm::StringRef variable, variable_format; 2107 error = FormatEntity::ExtractVariableInfo(format, variable, 2108 variable_format); 2109 if (error.Fail()) 2110 return error; 2111 bool verify_is_thread_id = false; 2112 Entry entry; 2113 if (!variable_format.empty()) { 2114 entry.printf_format = variable_format.str(); 2115 2116 // If the format contains a '%' we are going to assume this is 2117 // a printf style format. So if you want to format your thread ID 2118 // using "0x%llx" you can use: 2119 // ${thread.id%0x%llx} 2120 // 2121 // If there is no '%' in the format, then it is assumed to be a 2122 // LLDB format name, or one of the extended formats specified in 2123 // the switch statement below. 2124 2125 if (entry.printf_format.find('%') == std::string::npos) { 2126 bool clear_printf = false; 2127 2128 if (FormatManager::GetFormatFromCString( 2129 entry.printf_format.c_str(), false, entry.fmt)) { 2130 // We have an LLDB format, so clear the printf format 2131 clear_printf = true; 2132 } else if (entry.printf_format.size() == 1) { 2133 switch (entry.printf_format[0]) { 2134 case '@': // if this is an @ sign, print ObjC description 2135 entry.number = ValueObject:: 2136 eValueObjectRepresentationStyleLanguageSpecific; 2137 clear_printf = true; 2138 break; 2139 case 'V': // if this is a V, print the value using the default 2140 // format 2141 entry.number = 2142 ValueObject::eValueObjectRepresentationStyleValue; 2143 clear_printf = true; 2144 break; 2145 case 'L': // if this is an L, print the location of the value 2146 entry.number = 2147 ValueObject::eValueObjectRepresentationStyleLocation; 2148 clear_printf = true; 2149 break; 2150 case 'S': // if this is an S, print the summary after all 2151 entry.number = 2152 ValueObject::eValueObjectRepresentationStyleSummary; 2153 clear_printf = true; 2154 break; 2155 case '#': // if this is a '#', print the number of children 2156 entry.number = 2157 ValueObject::eValueObjectRepresentationStyleChildrenCount; 2158 clear_printf = true; 2159 break; 2160 case 'T': // if this is a 'T', print the type 2161 entry.number = 2162 ValueObject::eValueObjectRepresentationStyleType; 2163 clear_printf = true; 2164 break; 2165 case 'N': // if this is a 'N', print the name 2166 entry.number = 2167 ValueObject::eValueObjectRepresentationStyleName; 2168 clear_printf = true; 2169 break; 2170 case '>': // if this is a '>', print the expression path 2171 entry.number = ValueObject:: 2172 eValueObjectRepresentationStyleExpressionPath; 2173 clear_printf = true; 2174 break; 2175 default: 2176 error.SetErrorStringWithFormat("invalid format: '%s'", 2177 entry.printf_format.c_str()); 2178 return error; 2179 } 2180 } else if (FormatManager::GetFormatFromCString( 2181 entry.printf_format.c_str(), true, entry.fmt)) { 2182 clear_printf = true; 2183 } else if (entry.printf_format == "tid") { 2184 verify_is_thread_id = true; 2185 } else { 2186 error.SetErrorStringWithFormat("invalid format: '%s'", 2187 entry.printf_format.c_str()); 2188 return error; 2189 } 2190 2191 // Our format string turned out to not be a printf style format 2192 // so lets clear the string 2193 if (clear_printf) 2194 entry.printf_format.clear(); 2195 } 2196 } 2197 2198 // Check for dereferences 2199 if (variable[0] == '*') { 2200 entry.deref = true; 2201 variable = variable.drop_front(); 2202 } 2203 2204 error = ParseEntry(variable, &g_root, entry); 2205 if (error.Fail()) 2206 return error; 2207 2208 if (verify_is_thread_id) { 2209 if (entry.type != Entry::Type::ThreadID && 2210 entry.type != Entry::Type::ThreadProtocolID) { 2211 error.SetErrorString("the 'tid' format can only be used on " 2212 "${thread.id} and ${thread.protocol_id}"); 2213 } 2214 } 2215 2216 switch (entry.type) { 2217 case Entry::Type::Variable: 2218 case Entry::Type::VariableSynthetic: 2219 if (entry.number == 0) { 2220 if (entry.string.empty()) 2221 entry.number = 2222 ValueObject::eValueObjectRepresentationStyleValue; 2223 else 2224 entry.number = 2225 ValueObject::eValueObjectRepresentationStyleSummary; 2226 } 2227 break; 2228 default: 2229 // Make sure someone didn't try to dereference anything but ${var} 2230 // or ${svar} 2231 if (entry.deref) { 2232 error.SetErrorStringWithFormat( 2233 "${%s} can't be dereferenced, only ${var} and ${svar} can.", 2234 variable.str().c_str()); 2235 return error; 2236 } 2237 } 2238 // Check if this entry just wants to insert a constant string 2239 // value into the parent_entry, if so, insert the string with 2240 // AppendText, else append the entry to the parent_entry. 2241 if (entry.type == Entry::Type::InsertString) 2242 parent_entry.AppendText(entry.string.c_str()); 2243 else 2244 parent_entry.AppendEntry(std::move(entry)); 2245 } 2246 } 2247 break; 2248 } 2249 } 2250 return error; 2251 } 2252 2253 Error FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str, 2254 llvm::StringRef &variable_name, 2255 llvm::StringRef &variable_format) { 2256 Error error; 2257 variable_name = llvm::StringRef(); 2258 variable_format = llvm::StringRef(); 2259 2260 const size_t paren_pos = format_str.find('}'); 2261 if (paren_pos != llvm::StringRef::npos) { 2262 const size_t percent_pos = format_str.find('%'); 2263 if (percent_pos < paren_pos) { 2264 if (percent_pos > 0) { 2265 if (percent_pos > 1) 2266 variable_name = format_str.substr(0, percent_pos); 2267 variable_format = 2268 format_str.substr(percent_pos + 1, paren_pos - (percent_pos + 1)); 2269 } 2270 } else { 2271 variable_name = format_str.substr(0, paren_pos); 2272 } 2273 // Strip off elements and the formatting and the trailing '}' 2274 format_str = format_str.substr(paren_pos + 1); 2275 } else { 2276 error.SetErrorStringWithFormat( 2277 "missing terminating '}' character for '${%s'", 2278 format_str.str().c_str()); 2279 } 2280 return error; 2281 } 2282 2283 bool FormatEntity::FormatFileSpec(const FileSpec &file_spec, Stream &s, 2284 llvm::StringRef variable_name, 2285 llvm::StringRef variable_format) { 2286 if (variable_name.empty() || variable_name.equals(".fullpath")) { 2287 file_spec.Dump(&s); 2288 return true; 2289 } else if (variable_name.equals(".basename")) { 2290 s.PutCString(file_spec.GetFilename().AsCString("")); 2291 return true; 2292 } else if (variable_name.equals(".dirname")) { 2293 s.PutCString(file_spec.GetFilename().AsCString("")); 2294 return true; 2295 } 2296 return false; 2297 } 2298 2299 static std::string MakeMatch(const llvm::StringRef &prefix, 2300 const char *suffix) { 2301 std::string match(prefix.str()); 2302 match.append(suffix); 2303 return match; 2304 } 2305 2306 static void AddMatches(const FormatEntity::Entry::Definition *def, 2307 const llvm::StringRef &prefix, 2308 const llvm::StringRef &match_prefix, 2309 StringList &matches) { 2310 const size_t n = def->num_children; 2311 if (n > 0) { 2312 for (size_t i = 0; i < n; ++i) { 2313 std::string match = prefix.str(); 2314 if (match_prefix.empty()) 2315 matches.AppendString(MakeMatch(prefix, def->children[i].name)); 2316 else if (strncmp(def->children[i].name, match_prefix.data(), 2317 match_prefix.size()) == 0) 2318 matches.AppendString( 2319 MakeMatch(prefix, def->children[i].name + match_prefix.size())); 2320 } 2321 } 2322 } 2323 2324 size_t FormatEntity::AutoComplete(llvm::StringRef str, int match_start_point, 2325 int max_return_elements, bool &word_complete, 2326 StringList &matches) { 2327 word_complete = false; 2328 str = str.drop_front(match_start_point); 2329 matches.Clear(); 2330 2331 const size_t dollar_pos = str.rfind('$'); 2332 if (dollar_pos == llvm::StringRef::npos) 2333 return 0; 2334 2335 // Hitting TAB after $ at the end of the string add a "{" 2336 if (dollar_pos == str.size() - 1) { 2337 std::string match = str.str(); 2338 match.append("{"); 2339 matches.AppendString(match); 2340 return 1; 2341 } 2342 2343 if (str[dollar_pos + 1] != '{') 2344 return 0; 2345 2346 const size_t close_pos = str.find('}', dollar_pos + 2); 2347 if (close_pos != llvm::StringRef::npos) 2348 return 0; 2349 2350 const size_t format_pos = str.find('%', dollar_pos + 2); 2351 if (format_pos != llvm::StringRef::npos) 2352 return 0; 2353 2354 llvm::StringRef partial_variable(str.substr(dollar_pos + 2)); 2355 if (partial_variable.empty()) { 2356 // Suggest all top level entites as we are just past "${" 2357 AddMatches(&g_root, str, llvm::StringRef(), matches); 2358 return matches.GetSize(); 2359 } 2360 2361 // We have a partially specified variable, find it 2362 llvm::StringRef remainder; 2363 const FormatEntity::Entry::Definition *entry_def = 2364 FindEntry(partial_variable, &g_root, remainder); 2365 if (!entry_def) 2366 return 0; 2367 2368 const size_t n = entry_def->num_children; 2369 2370 if (remainder.empty()) { 2371 // Exact match 2372 if (n > 0) { 2373 // "${thread.info" <TAB> 2374 matches.AppendString(MakeMatch(str, ".")); 2375 } else { 2376 // "${thread.id" <TAB> 2377 matches.AppendString(MakeMatch(str, "}")); 2378 word_complete = true; 2379 } 2380 } else if (remainder.equals(".")) { 2381 // "${thread." <TAB> 2382 AddMatches(entry_def, str, llvm::StringRef(), matches); 2383 } else { 2384 // We have a partial match 2385 // "${thre" <TAB> 2386 AddMatches(entry_def, str, remainder, matches); 2387 } 2388 return matches.GetSize(); 2389 } 2390