1 //===-- FormatEntity.cpp --------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Core/FormatEntity.h"
11 #include "lldb/Core/Address.h"
12 #include "lldb/Core/AddressRange.h"
13 #include "lldb/Core/Debugger.h"
14 #include "lldb/Core/DumpRegisterValue.h"
15 #include "lldb/Core/Module.h"
16 #include "lldb/DataFormatters/DataVisualization.h"
17 #include "lldb/DataFormatters/FormatClasses.h"
18 #include "lldb/DataFormatters/FormatManager.h"
19 #include "lldb/DataFormatters/TypeSummary.h"
20 #include "lldb/Expression/ExpressionVariable.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Symbol/Block.h"
23 #include "lldb/Symbol/CompileUnit.h"
24 #include "lldb/Symbol/CompilerType.h"
25 #include "lldb/Symbol/Function.h"
26 #include "lldb/Symbol/LineEntry.h"
27 #include "lldb/Symbol/Symbol.h"
28 #include "lldb/Symbol/SymbolContext.h"
29 #include "lldb/Symbol/VariableList.h"
30 #include "lldb/Target/ExecutionContext.h"
31 #include "lldb/Target/ExecutionContextScope.h"
32 #include "lldb/Target/Language.h"
33 #include "lldb/Target/Process.h"
34 #include "lldb/Target/RegisterContext.h"
35 #include "lldb/Target/SectionLoadList.h"
36 #include "lldb/Target/StackFrame.h"
37 #include "lldb/Target/StopInfo.h"
38 #include "lldb/Target/Target.h"
39 #include "lldb/Target/Thread.h"
40 #include "lldb/Utility/AnsiTerminal.h"
41 #include "lldb/Utility/ArchSpec.h"
42 #include "lldb/Utility/CompletionRequest.h"
43 #include "lldb/Utility/ConstString.h"
44 #include "lldb/Utility/FileSpec.h"
45 #include "lldb/Utility/LLDBLog.h"
46 #include "lldb/Utility/Log.h"
47 #include "lldb/Utility/RegisterValue.h"
48 #include "lldb/Utility/Status.h"
49 #include "lldb/Utility/Stream.h"
50 #include "lldb/Utility/StreamString.h"
51 #include "lldb/Utility/StringList.h"
52 #include "lldb/Utility/StructuredData.h"
53 #include "lldb/ValueObject/ValueObject.h"
54 #include "lldb/ValueObject/ValueObjectVariable.h"
55 #include "lldb/lldb-defines.h"
56 #include "lldb/lldb-forward.h"
57 #include "llvm/ADT/STLExtras.h"
58 #include "llvm/ADT/StringRef.h"
59 #include "llvm/Support/Compiler.h"
60 #include "llvm/Support/Regex.h"
61 #include "llvm/TargetParser/Triple.h"
69 #include <type_traits>
72 namespace lldb_private
{
73 class ScriptInterpreter
;
75 namespace lldb_private
{
80 using namespace lldb_private
;
82 using Definition
= lldb_private::FormatEntity::Entry::Definition
;
83 using Entry
= FormatEntity::Entry
;
84 using EntryType
= FormatEntity::Entry::Type
;
86 enum FileKind
{ FileError
= 0, Basename
, Dirname
, Fullpath
};
88 constexpr Definition g_string_entry
[] = {
89 Definition("*", EntryType::ParentString
)};
91 constexpr Definition g_addr_entries
[] = {
92 Definition("load", EntryType::AddressLoad
),
93 Definition("file", EntryType::AddressFile
)};
95 constexpr Definition g_file_child_entries
[] = {
96 Definition("basename", EntryType::ParentNumber
, FileKind::Basename
),
97 Definition("dirname", EntryType::ParentNumber
, FileKind::Dirname
),
98 Definition("fullpath", EntryType::ParentNumber
, FileKind::Fullpath
)};
100 constexpr Definition g_frame_child_entries
[] = {
101 Definition("index", EntryType::FrameIndex
),
102 Definition("pc", EntryType::FrameRegisterPC
),
103 Definition("fp", EntryType::FrameRegisterFP
),
104 Definition("sp", EntryType::FrameRegisterSP
),
105 Definition("flags", EntryType::FrameRegisterFlags
),
106 Definition("no-debug", EntryType::FrameNoDebug
),
107 Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName
,
109 Definition("is-artificial", EntryType::FrameIsArtificial
),
112 constexpr Definition g_function_child_entries
[] = {
113 Definition("id", EntryType::FunctionID
),
114 Definition("name", EntryType::FunctionName
),
115 Definition("name-without-args", EntryType::FunctionNameNoArgs
),
116 Definition("name-with-args", EntryType::FunctionNameWithArgs
),
117 Definition("mangled-name", EntryType::FunctionMangledName
),
118 Definition("addr-offset", EntryType::FunctionAddrOffset
),
119 Definition("concrete-only-addr-offset-no-padding",
120 EntryType::FunctionAddrOffsetConcrete
),
121 Definition("line-offset", EntryType::FunctionLineOffset
),
122 Definition("pc-offset", EntryType::FunctionPCOffset
),
123 Definition("initial-function", EntryType::FunctionInitial
),
124 Definition("changed", EntryType::FunctionChanged
),
125 Definition("is-optimized", EntryType::FunctionIsOptimized
)};
127 constexpr Definition g_line_child_entries
[] = {
128 Entry::DefinitionWithChildren("file", EntryType::LineEntryFile
,
129 g_file_child_entries
),
130 Definition("number", EntryType::LineEntryLineNumber
),
131 Definition("column", EntryType::LineEntryColumn
),
132 Definition("start-addr", EntryType::LineEntryStartAddress
),
133 Definition("end-addr", EntryType::LineEntryEndAddress
),
136 constexpr Definition g_module_child_entries
[] = {Entry::DefinitionWithChildren(
137 "file", EntryType::ModuleFile
, g_file_child_entries
)};
139 constexpr Definition g_process_child_entries
[] = {
140 Definition("id", EntryType::ProcessID
),
141 Definition("name", EntryType::ProcessFile
, FileKind::Basename
),
142 Entry::DefinitionWithChildren("file", EntryType::ProcessFile
,
143 g_file_child_entries
)};
145 constexpr Definition g_svar_child_entries
[] = {
146 Definition("*", EntryType::ParentString
)};
148 constexpr Definition g_var_child_entries
[] = {
149 Definition("*", EntryType::ParentString
)};
151 constexpr Definition g_thread_child_entries
[] = {
152 Definition("id", EntryType::ThreadID
),
153 Definition("protocol_id", EntryType::ThreadProtocolID
),
154 Definition("index", EntryType::ThreadIndexID
),
155 Entry::DefinitionWithChildren("info", EntryType::ThreadInfo
,
157 Definition("queue", EntryType::ThreadQueue
),
158 Definition("name", EntryType::ThreadName
),
159 Definition("stop-reason", EntryType::ThreadStopReason
),
160 Definition("stop-reason-raw", EntryType::ThreadStopReasonRaw
),
161 Definition("return-value", EntryType::ThreadReturnValue
),
162 Definition("completed-expression", EntryType::ThreadCompletedExpression
)};
164 constexpr Definition g_target_child_entries
[] = {
165 Definition("arch", EntryType::TargetArch
)};
167 #define _TO_STR2(_val) #_val
168 #define _TO_STR(_val) _TO_STR2(_val)
170 constexpr Definition g_ansi_fg_entries
[] = {
172 ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_BLACK
) ANSI_ESC_END
),
173 Definition("red", ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_RED
) ANSI_ESC_END
),
175 ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_GREEN
) ANSI_ESC_END
),
177 ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_YELLOW
) ANSI_ESC_END
),
178 Definition("blue", ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_BLUE
) ANSI_ESC_END
),
180 ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_PURPLE
) ANSI_ESC_END
),
181 Definition("cyan", ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_CYAN
) ANSI_ESC_END
),
183 ANSI_ESC_START
_TO_STR(ANSI_FG_COLOR_WHITE
) ANSI_ESC_END
),
186 constexpr Definition g_ansi_bg_entries
[] = {
188 ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_BLACK
) ANSI_ESC_END
),
189 Definition("red", ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_RED
) ANSI_ESC_END
),
191 ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_GREEN
) ANSI_ESC_END
),
193 ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_YELLOW
) ANSI_ESC_END
),
194 Definition("blue", ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_BLUE
) ANSI_ESC_END
),
196 ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_PURPLE
) ANSI_ESC_END
),
197 Definition("cyan", ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_CYAN
) ANSI_ESC_END
),
199 ANSI_ESC_START
_TO_STR(ANSI_BG_COLOR_WHITE
) ANSI_ESC_END
),
202 constexpr Definition g_ansi_entries
[] = {
203 Entry::DefinitionWithChildren("fg", EntryType::Invalid
, g_ansi_fg_entries
),
204 Entry::DefinitionWithChildren("bg", EntryType::Invalid
, g_ansi_bg_entries
),
205 Definition("normal", ANSI_ESC_START
_TO_STR(ANSI_CTRL_NORMAL
) ANSI_ESC_END
),
206 Definition("bold", ANSI_ESC_START
_TO_STR(ANSI_CTRL_BOLD
) ANSI_ESC_END
),
207 Definition("faint", ANSI_ESC_START
_TO_STR(ANSI_CTRL_FAINT
) ANSI_ESC_END
),
208 Definition("italic", ANSI_ESC_START
_TO_STR(ANSI_CTRL_ITALIC
) ANSI_ESC_END
),
209 Definition("underline",
210 ANSI_ESC_START
_TO_STR(ANSI_CTRL_UNDERLINE
) ANSI_ESC_END
),
211 Definition("slow-blink",
212 ANSI_ESC_START
_TO_STR(ANSI_CTRL_SLOW_BLINK
) ANSI_ESC_END
),
213 Definition("fast-blink",
214 ANSI_ESC_START
_TO_STR(ANSI_CTRL_FAST_BLINK
) ANSI_ESC_END
),
215 Definition("negative",
216 ANSI_ESC_START
_TO_STR(ANSI_CTRL_IMAGE_NEGATIVE
) ANSI_ESC_END
),
217 Definition("conceal",
218 ANSI_ESC_START
_TO_STR(ANSI_CTRL_CONCEAL
) ANSI_ESC_END
),
219 Definition("crossed-out",
220 ANSI_ESC_START
_TO_STR(ANSI_CTRL_CROSSED_OUT
) ANSI_ESC_END
),
223 constexpr Definition g_script_child_entries
[] = {
224 Definition("frame", EntryType::ScriptFrame
),
225 Definition("process", EntryType::ScriptProcess
),
226 Definition("target", EntryType::ScriptTarget
),
227 Definition("thread", EntryType::ScriptThread
),
228 Definition("var", EntryType::ScriptVariable
),
229 Definition("svar", EntryType::ScriptVariableSynthetic
),
230 Definition("thread", EntryType::ScriptThread
)};
232 constexpr Definition g_top_level_entries
[] = {
233 Entry::DefinitionWithChildren("addr", EntryType::AddressLoadOrFile
,
235 Definition("addr-file-or-load", EntryType::AddressLoadOrFile
),
236 Entry::DefinitionWithChildren("ansi", EntryType::Invalid
, g_ansi_entries
),
237 Definition("current-pc-arrow", EntryType::CurrentPCArrow
),
238 Entry::DefinitionWithChildren("file", EntryType::File
,
239 g_file_child_entries
),
240 Definition("language", EntryType::Lang
),
241 Entry::DefinitionWithChildren("frame", EntryType::Invalid
,
242 g_frame_child_entries
),
243 Entry::DefinitionWithChildren("function", EntryType::Invalid
,
244 g_function_child_entries
),
245 Entry::DefinitionWithChildren("line", EntryType::Invalid
,
246 g_line_child_entries
),
247 Entry::DefinitionWithChildren("module", EntryType::Invalid
,
248 g_module_child_entries
),
249 Entry::DefinitionWithChildren("process", EntryType::Invalid
,
250 g_process_child_entries
),
251 Entry::DefinitionWithChildren("script", EntryType::Invalid
,
252 g_script_child_entries
),
253 Entry::DefinitionWithChildren("svar", EntryType::VariableSynthetic
,
254 g_svar_child_entries
, true),
255 Entry::DefinitionWithChildren("thread", EntryType::Invalid
,
256 g_thread_child_entries
),
257 Entry::DefinitionWithChildren("target", EntryType::Invalid
,
258 g_target_child_entries
),
259 Entry::DefinitionWithChildren("var", EntryType::Variable
,
260 g_var_child_entries
, true)};
262 constexpr Definition g_root
= Entry::DefinitionWithChildren(
263 "<root>", EntryType::Root
, g_top_level_entries
);
265 FormatEntity::Entry::Entry(llvm::StringRef s
)
266 : string(s
.data(), s
.size()), printf_format(), children(),
267 type(Type::String
) {}
269 FormatEntity::Entry::Entry(char ch
)
270 : string(1, ch
), printf_format(), children(), type(Type::String
) {}
272 void FormatEntity::Entry::AppendChar(char ch
) {
273 if (children
.empty() || children
.back().type
!= Entry::Type::String
)
274 children
.push_back(Entry(ch
));
276 children
.back().string
.append(1, ch
);
279 void FormatEntity::Entry::AppendText(const llvm::StringRef
&s
) {
280 if (children
.empty() || children
.back().type
!= Entry::Type::String
)
281 children
.push_back(Entry(s
));
283 children
.back().string
.append(s
.data(), s
.size());
286 void FormatEntity::Entry::AppendText(const char *cstr
) {
287 return AppendText(llvm::StringRef(cstr
));
290 #define ENUM_TO_CSTR(eee) \
291 case FormatEntity::Entry::Type::eee: \
294 const char *FormatEntity::Entry::TypeToCString(Type t
) {
296 ENUM_TO_CSTR(Invalid
);
297 ENUM_TO_CSTR(ParentNumber
);
298 ENUM_TO_CSTR(ParentString
);
299 ENUM_TO_CSTR(EscapeCode
);
301 ENUM_TO_CSTR(String
);
303 ENUM_TO_CSTR(Variable
);
304 ENUM_TO_CSTR(VariableSynthetic
);
305 ENUM_TO_CSTR(ScriptVariable
);
306 ENUM_TO_CSTR(ScriptVariableSynthetic
);
307 ENUM_TO_CSTR(AddressLoad
);
308 ENUM_TO_CSTR(AddressFile
);
309 ENUM_TO_CSTR(AddressLoadOrFile
);
310 ENUM_TO_CSTR(ProcessID
);
311 ENUM_TO_CSTR(ProcessFile
);
312 ENUM_TO_CSTR(ScriptProcess
);
313 ENUM_TO_CSTR(ThreadID
);
314 ENUM_TO_CSTR(ThreadProtocolID
);
315 ENUM_TO_CSTR(ThreadIndexID
);
316 ENUM_TO_CSTR(ThreadName
);
317 ENUM_TO_CSTR(ThreadQueue
);
318 ENUM_TO_CSTR(ThreadStopReason
);
319 ENUM_TO_CSTR(ThreadStopReasonRaw
);
320 ENUM_TO_CSTR(ThreadReturnValue
);
321 ENUM_TO_CSTR(ThreadCompletedExpression
);
322 ENUM_TO_CSTR(ScriptThread
);
323 ENUM_TO_CSTR(ThreadInfo
);
324 ENUM_TO_CSTR(TargetArch
);
325 ENUM_TO_CSTR(ScriptTarget
);
326 ENUM_TO_CSTR(ModuleFile
);
329 ENUM_TO_CSTR(FrameIndex
);
330 ENUM_TO_CSTR(FrameNoDebug
);
331 ENUM_TO_CSTR(FrameRegisterPC
);
332 ENUM_TO_CSTR(FrameRegisterSP
);
333 ENUM_TO_CSTR(FrameRegisterFP
);
334 ENUM_TO_CSTR(FrameRegisterFlags
);
335 ENUM_TO_CSTR(FrameRegisterByName
);
336 ENUM_TO_CSTR(FrameIsArtificial
);
337 ENUM_TO_CSTR(ScriptFrame
);
338 ENUM_TO_CSTR(FunctionID
);
339 ENUM_TO_CSTR(FunctionDidChange
);
340 ENUM_TO_CSTR(FunctionInitialFunction
);
341 ENUM_TO_CSTR(FunctionName
);
342 ENUM_TO_CSTR(FunctionNameWithArgs
);
343 ENUM_TO_CSTR(FunctionNameNoArgs
);
344 ENUM_TO_CSTR(FunctionMangledName
);
345 ENUM_TO_CSTR(FunctionAddrOffset
);
346 ENUM_TO_CSTR(FunctionAddrOffsetConcrete
);
347 ENUM_TO_CSTR(FunctionLineOffset
);
348 ENUM_TO_CSTR(FunctionPCOffset
);
349 ENUM_TO_CSTR(FunctionInitial
);
350 ENUM_TO_CSTR(FunctionChanged
);
351 ENUM_TO_CSTR(FunctionIsOptimized
);
352 ENUM_TO_CSTR(LineEntryFile
);
353 ENUM_TO_CSTR(LineEntryLineNumber
);
354 ENUM_TO_CSTR(LineEntryColumn
);
355 ENUM_TO_CSTR(LineEntryStartAddress
);
356 ENUM_TO_CSTR(LineEntryEndAddress
);
357 ENUM_TO_CSTR(CurrentPCArrow
);
364 void FormatEntity::Entry::Dump(Stream
&s
, int depth
) const {
365 s
.Printf("%*.*s%-20s: ", depth
* 2, depth
* 2, "", TypeToCString(type
));
366 if (fmt
!= eFormatDefault
)
367 s
.Printf("lldb-format = %s, ", FormatManager::GetFormatAsCString(fmt
));
369 s
.Printf("string = \"%s\"", string
.c_str());
370 if (!printf_format
.empty())
371 s
.Printf("printf_format = \"%s\"", printf_format
.c_str());
373 s
.Printf("number = %" PRIu64
" (0x%" PRIx64
"), ", number
, number
);
375 s
.Printf("deref = true, ");
377 for (const auto &child
: children
) {
378 child
.Dump(s
, depth
+ 1);
382 template <typename T
>
383 static bool RunScriptFormatKeyword(Stream
&s
, const SymbolContext
*sc
,
384 const ExecutionContext
*exe_ctx
, T t
,
385 const char *script_function_name
) {
386 Target
*target
= Target::GetTargetFromContexts(exe_ctx
, sc
);
389 ScriptInterpreter
*script_interpreter
=
390 target
->GetDebugger().GetScriptInterpreter();
391 if (script_interpreter
) {
393 std::string script_output
;
395 if (script_interpreter
->RunScriptFormatKeyword(script_function_name
, t
,
396 script_output
, error
) &&
398 s
.Printf("%s", script_output
.c_str());
401 s
.Printf("<error: %s>", error
.AsCString());
408 static bool DumpAddressAndContent(Stream
&s
, const SymbolContext
*sc
,
409 const ExecutionContext
*exe_ctx
,
411 bool print_file_addr_or_load_addr
) {
412 Target
*target
= Target::GetTargetFromContexts(exe_ctx
, sc
);
414 addr_t vaddr
= LLDB_INVALID_ADDRESS
;
415 if (target
&& !target
->GetSectionLoadList().IsEmpty())
416 vaddr
= addr
.GetLoadAddress(target
);
417 if (vaddr
== LLDB_INVALID_ADDRESS
)
418 vaddr
= addr
.GetFileAddress();
419 if (vaddr
== LLDB_INVALID_ADDRESS
)
424 addr_width
= target
->GetArchitecture().GetAddressByteSize() * 2;
428 if (print_file_addr_or_load_addr
) {
429 ExecutionContextScope
*exe_scope
=
430 exe_ctx
? exe_ctx
->GetBestExecutionContextScope() : nullptr;
431 addr
.Dump(&s
, exe_scope
, Address::DumpStyleLoadAddress
,
432 Address::DumpStyleModuleWithFileAddress
, 0);
434 s
.Printf("0x%*.*" PRIx64
, addr_width
, addr_width
, vaddr
);
440 static bool DumpAddressOffsetFromFunction(Stream
&s
, const SymbolContext
*sc
,
441 const ExecutionContext
*exe_ctx
,
442 const Address
&format_addr
,
443 bool concrete_only
, bool no_padding
,
444 bool print_zero_offsets
) {
445 if (format_addr
.IsValid()) {
450 func_addr
= sc
->function
->GetAddressRange().GetBaseAddress();
451 if (sc
->block
&& !concrete_only
) {
452 // Check to make sure we aren't in an inline function. If we are, use
453 // the inline block range that contains "format_addr" since blocks
454 // can be discontiguous.
455 Block
*inline_block
= sc
->block
->GetContainingInlinedBlock();
456 AddressRange inline_range
;
457 if (inline_block
&& inline_block
->GetRangeContainingAddress(
458 format_addr
, inline_range
))
459 func_addr
= inline_range
.GetBaseAddress();
461 } else if (sc
->symbol
&& sc
->symbol
->ValueIsAddress())
462 func_addr
= sc
->symbol
->GetAddressRef();
465 if (func_addr
.IsValid()) {
466 const char *addr_offset_padding
= no_padding
? "" : " ";
468 if (func_addr
.GetSection() == format_addr
.GetSection()) {
469 addr_t func_file_addr
= func_addr
.GetFileAddress();
470 addr_t addr_file_addr
= format_addr
.GetFileAddress();
471 if (addr_file_addr
> func_file_addr
||
472 (addr_file_addr
== func_file_addr
&& print_zero_offsets
)) {
473 s
.Printf("%s+%s%" PRIu64
, addr_offset_padding
, addr_offset_padding
,
474 addr_file_addr
- func_file_addr
);
475 } else if (addr_file_addr
< func_file_addr
) {
476 s
.Printf("%s-%s%" PRIu64
, addr_offset_padding
, addr_offset_padding
,
477 func_file_addr
- addr_file_addr
);
481 Target
*target
= Target::GetTargetFromContexts(exe_ctx
, sc
);
483 addr_t func_load_addr
= func_addr
.GetLoadAddress(target
);
484 addr_t addr_load_addr
= format_addr
.GetLoadAddress(target
);
485 if (addr_load_addr
> func_load_addr
||
486 (addr_load_addr
== func_load_addr
&& print_zero_offsets
)) {
487 s
.Printf("%s+%s%" PRIu64
, addr_offset_padding
, addr_offset_padding
,
488 addr_load_addr
- func_load_addr
);
489 } else if (addr_load_addr
< func_load_addr
) {
490 s
.Printf("%s-%s%" PRIu64
, addr_offset_padding
, addr_offset_padding
,
491 func_load_addr
- addr_load_addr
);
501 static bool ScanBracketedRange(llvm::StringRef subpath
,
502 size_t &close_bracket_index
,
503 const char *&var_name_final_if_array_range
,
504 int64_t &index_lower
, int64_t &index_higher
) {
505 Log
*log
= GetLog(LLDBLog::DataFormatters
);
506 close_bracket_index
= llvm::StringRef::npos
;
507 const size_t open_bracket_index
= subpath
.find('[');
508 if (open_bracket_index
== llvm::StringRef::npos
) {
510 "[ScanBracketedRange] no bracketed range, skipping entirely");
514 close_bracket_index
= subpath
.find(']', open_bracket_index
+ 1);
516 if (close_bracket_index
== llvm::StringRef::npos
) {
518 "[ScanBracketedRange] no bracketed range, skipping entirely");
521 var_name_final_if_array_range
= subpath
.data() + open_bracket_index
;
523 if (close_bracket_index
- open_bracket_index
== 1) {
526 "[ScanBracketedRange] '[]' detected.. going from 0 to end of data");
529 const size_t separator_index
= subpath
.find('-', open_bracket_index
+ 1);
531 if (separator_index
== llvm::StringRef::npos
) {
532 const char *index_lower_cstr
= subpath
.data() + open_bracket_index
+ 1;
533 index_lower
= ::strtoul(index_lower_cstr
, nullptr, 0);
534 index_higher
= index_lower
;
536 "[ScanBracketedRange] [%" PRId64
537 "] detected, high index is same",
540 const char *index_lower_cstr
= subpath
.data() + open_bracket_index
+ 1;
541 const char *index_higher_cstr
= subpath
.data() + separator_index
+ 1;
542 index_lower
= ::strtoul(index_lower_cstr
, nullptr, 0);
543 index_higher
= ::strtoul(index_higher_cstr
, nullptr, 0);
545 "[ScanBracketedRange] [%" PRId64
"-%" PRId64
"] detected",
546 index_lower
, index_higher
);
548 if (index_lower
> index_higher
&& index_higher
> 0) {
549 LLDB_LOGF(log
, "[ScanBracketedRange] swapping indices");
550 const int64_t temp
= index_lower
;
551 index_lower
= index_higher
;
559 static bool DumpFile(Stream
&s
, const FileSpec
&file
, FileKind file_kind
) {
561 case FileKind::FileError
:
564 case FileKind::Basename
:
565 if (file
.GetFilename()) {
566 s
<< file
.GetFilename();
571 case FileKind::Dirname
:
572 if (file
.GetDirectory()) {
573 s
<< file
.GetDirectory();
578 case FileKind::Fullpath
:
588 static bool DumpRegister(Stream
&s
, StackFrame
*frame
, RegisterKind reg_kind
,
589 uint32_t reg_num
, Format format
) {
591 RegisterContext
*reg_ctx
= frame
->GetRegisterContext().get();
594 const uint32_t lldb_reg_num
=
595 reg_ctx
->ConvertRegisterKindToRegisterNumber(reg_kind
, reg_num
);
596 if (lldb_reg_num
!= LLDB_INVALID_REGNUM
) {
597 const RegisterInfo
*reg_info
=
598 reg_ctx
->GetRegisterInfoAtIndex(lldb_reg_num
);
600 RegisterValue reg_value
;
601 if (reg_ctx
->ReadRegister(reg_info
, reg_value
)) {
602 DumpRegisterValue(reg_value
, s
, *reg_info
, false, false, format
);
612 static ValueObjectSP
ExpandIndexedExpression(ValueObject
*valobj
, size_t index
,
613 bool deref_pointer
) {
614 Log
*log
= GetLog(LLDBLog::DataFormatters
);
615 std::string name_to_deref
= llvm::formatv("[{0}]", index
);
616 LLDB_LOG(log
, "[ExpandIndexedExpression] name to deref: {0}", name_to_deref
);
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 name_to_deref
, &reason_to_stop
, &final_value_type
, options
, &what_next
);
627 "[ExpandIndexedExpression] ERROR: why stopping = %d,"
628 " final_value_type %d",
629 reason_to_stop
, final_value_type
);
632 "[ExpandIndexedExpression] ALL RIGHT: why stopping = %d,"
633 " final_value_type %d",
634 reason_to_stop
, final_value_type
);
639 static char ConvertValueObjectStyleToChar(
640 ValueObject::ValueObjectRepresentationStyle style
) {
642 case ValueObject::eValueObjectRepresentationStyleLanguageSpecific
:
644 case ValueObject::eValueObjectRepresentationStyleValue
:
646 case ValueObject::eValueObjectRepresentationStyleLocation
:
648 case ValueObject::eValueObjectRepresentationStyleSummary
:
650 case ValueObject::eValueObjectRepresentationStyleChildrenCount
:
652 case ValueObject::eValueObjectRepresentationStyleType
:
654 case ValueObject::eValueObjectRepresentationStyleName
:
656 case ValueObject::eValueObjectRepresentationStyleExpressionPath
:
662 /// Options supported by format_provider<T> for integral arithmetic types.
663 /// See table in FormatProviders.h.
664 static llvm::Regex LLVMFormatPattern
{"x[-+]?\\d*|n|d", llvm::Regex::IgnoreCase
};
666 static bool DumpValueWithLLVMFormat(Stream
&s
, llvm::StringRef options
,
667 ValueObject
&valobj
) {
668 std::string formatted
;
669 std::string llvm_format
= ("{0:" + options
+ "}").str();
671 auto type_info
= valobj
.GetTypeInfo();
672 if ((type_info
& eTypeIsInteger
) && LLVMFormatPattern
.match(options
)) {
673 if (type_info
& eTypeIsSigned
) {
674 bool success
= false;
675 int64_t integer
= valobj
.GetValueAsSigned(0, &success
);
677 formatted
= llvm::formatv(llvm_format
.data(), integer
);
679 bool success
= false;
680 uint64_t integer
= valobj
.GetValueAsUnsigned(0, &success
);
682 formatted
= llvm::formatv(llvm_format
.data(), integer
);
686 if (formatted
.empty())
689 s
.Write(formatted
.data(), formatted
.size());
693 static bool DumpValue(Stream
&s
, const SymbolContext
*sc
,
694 const ExecutionContext
*exe_ctx
,
695 const FormatEntity::Entry
&entry
, ValueObject
*valobj
) {
696 if (valobj
== nullptr)
699 Log
*log
= GetLog(LLDBLog::DataFormatters
);
700 Format custom_format
= eFormatInvalid
;
701 ValueObject::ValueObjectRepresentationStyle val_obj_display
=
703 ? ValueObject::eValueObjectRepresentationStyleValue
704 : ValueObject::eValueObjectRepresentationStyleSummary
;
706 bool do_deref_pointer
= entry
.deref
;
707 bool is_script
= false;
708 switch (entry
.type
) {
709 case FormatEntity::Entry::Type::ScriptVariable
:
713 case FormatEntity::Entry::Type::Variable
:
714 custom_format
= entry
.fmt
;
715 val_obj_display
= (ValueObject::ValueObjectRepresentationStyle
)entry
.number
;
718 case FormatEntity::Entry::Type::ScriptVariableSynthetic
:
721 case FormatEntity::Entry::Type::VariableSynthetic
:
722 custom_format
= entry
.fmt
;
723 val_obj_display
= (ValueObject::ValueObjectRepresentationStyle
)entry
.number
;
724 if (!valobj
->IsSynthetic()) {
725 valobj
= valobj
->GetSyntheticValue().get();
726 if (valobj
== nullptr)
735 ValueObject::ExpressionPathAftermath what_next
=
736 (do_deref_pointer
? ValueObject::eExpressionPathAftermathDereference
737 : ValueObject::eExpressionPathAftermathNothing
);
738 ValueObject::GetValueForExpressionPathOptions options
;
739 options
.DontCheckDotVsArrowSyntax()
740 .DoAllowBitfieldSyntax()
741 .DoAllowFragileIVar()
742 .SetSyntheticChildrenTraversal(
743 ValueObject::GetValueForExpressionPathOptions::
744 SyntheticChildrenTraversal::Both
);
745 ValueObject
*target
= nullptr;
746 const char *var_name_final_if_array_range
= nullptr;
747 size_t close_bracket_index
= llvm::StringRef::npos
;
748 int64_t index_lower
= -1;
749 int64_t index_higher
= -1;
750 bool is_array_range
= false;
751 bool was_plain_var
= false;
752 bool was_var_format
= false;
753 bool was_var_indexed
= false;
754 ValueObject::ExpressionPathScanEndReason reason_to_stop
=
755 ValueObject::eExpressionPathScanEndReasonEndOfString
;
756 ValueObject::ExpressionPathEndResultType final_value_type
=
757 ValueObject::eExpressionPathEndResultTypePlain
;
760 return RunScriptFormatKeyword(s
, sc
, exe_ctx
, valobj
, entry
.string
.c_str());
763 auto split
= llvm::StringRef(entry
.string
).split(':');
764 auto subpath
= split
.first
;
765 auto llvm_format
= split
.second
;
767 // simplest case ${var}, just print valobj's value
768 if (subpath
.empty()) {
769 if (entry
.printf_format
.empty() && entry
.fmt
== eFormatDefault
&&
770 entry
.number
== ValueObject::eValueObjectRepresentationStyleValue
)
771 was_plain_var
= true;
773 was_var_format
= true;
775 } else // this is ${var.something} or multiple .something nested
777 if (subpath
[0] == '[')
778 was_var_indexed
= true;
779 ScanBracketedRange(subpath
, close_bracket_index
,
780 var_name_final_if_array_range
, index_lower
,
785 LLDB_LOG(log
, "[Debugger::FormatPrompt] symbol to expand: {0}", subpath
);
789 ->GetValueForExpressionPath(subpath
, &reason_to_stop
,
790 &final_value_type
, options
, &what_next
)
795 "[Debugger::FormatPrompt] ERROR: why stopping = %d,"
796 " final_value_type %d",
797 reason_to_stop
, final_value_type
);
801 "[Debugger::FormatPrompt] ALL RIGHT: why stopping = %d,"
802 " final_value_type %d",
803 reason_to_stop
, final_value_type
);
805 ->GetQualifiedRepresentationIfAvailable(
806 target
->GetDynamicValueType(), true)
813 ValueObject::eExpressionPathEndResultTypeBoundedRange
||
815 ValueObject::eExpressionPathEndResultTypeUnboundedRange
);
818 (what_next
== ValueObject::eExpressionPathAftermathDereference
);
820 if (do_deref_pointer
&& !is_array_range
) {
821 // I have not deref-ed yet, let's do it
822 // this happens when we are not going through
823 // GetValueForVariableExpressionPath to get to the target ValueObject
825 target
= target
->Dereference(error
).get();
827 LLDB_LOGF(log
, "[Debugger::FormatPrompt] ERROR: %s\n",
828 error
.AsCString("unknown"));
831 do_deref_pointer
= false;
835 LLDB_LOGF(log
, "[Debugger::FormatPrompt] could not calculate target for "
836 "prompt expression");
840 // we do not want to use the summary for a bitfield of type T:n if we were
841 // originally dealing with just a T - that would get us into an endless
843 if (target
->IsBitfield() && was_var_indexed
) {
844 // TODO: check for a (T:n)-specific summary - we should still obey that
845 StreamString bitfield_name
;
846 bitfield_name
.Printf("%s:%d", target
->GetTypeName().AsCString(),
847 target
->GetBitfieldBitSize());
848 auto type_sp
= std::make_shared
<TypeNameSpecifierImpl
>(
849 bitfield_name
.GetString(), lldb::eFormatterMatchExact
);
850 if (val_obj_display
==
851 ValueObject::eValueObjectRepresentationStyleSummary
&&
852 !DataVisualization::GetSummaryForType(type_sp
))
853 val_obj_display
= ValueObject::eValueObjectRepresentationStyleValue
;
856 // TODO use flags for these
857 const uint32_t type_info_flags
=
858 target
->GetCompilerType().GetTypeInfo(nullptr);
859 bool is_array
= (type_info_flags
& eTypeIsArray
) != 0;
860 bool is_pointer
= (type_info_flags
& eTypeIsPointer
) != 0;
861 bool is_aggregate
= target
->GetCompilerType().IsAggregateType();
863 if ((is_array
|| is_pointer
) && (!is_array_range
) &&
865 ValueObject::eValueObjectRepresentationStyleValue
) // this should be
870 StreamString str_temp
;
872 "[Debugger::FormatPrompt] I am into array || pointer && !range");
874 if (target
->HasSpecialPrintableRepresentation(val_obj_display
,
876 // try to use the special cases
877 bool success
= target
->DumpPrintableRepresentation(
878 str_temp
, val_obj_display
, custom_format
);
879 LLDB_LOGF(log
, "[Debugger::FormatPrompt] special cases did%s match",
880 success
? "" : "n't");
884 s
<< str_temp
.GetString();
887 if (was_plain_var
) // if ${var}
889 s
<< target
->GetTypeName() << " @ " << target
->GetLocationAsCString();
890 } else if (is_pointer
) // if pointer, value is the address stored
892 target
->DumpPrintableRepresentation(
893 s
, val_obj_display
, custom_format
,
894 ValueObject::PrintableRepresentationSpecialCases::eDisable
);
900 // if directly trying to print ${var}, and this is an aggregate, display a
901 // nice type @ location message
902 if (is_aggregate
&& was_plain_var
) {
903 s
<< target
->GetTypeName() << " @ " << target
->GetLocationAsCString();
907 // if directly trying to print ${var%V}, and this is an aggregate, do not let
912 ValueObject::eValueObjectRepresentationStyleValue
))) {
913 s
<< "<invalid use of aggregate type>";
917 if (!is_array_range
) {
918 if (!llvm_format
.empty()) {
919 if (DumpValueWithLLVMFormat(s
, llvm_format
, *target
)) {
920 LLDB_LOGF(log
, "dumping using llvm format");
925 "empty output using llvm format '{0}' - with type info flags {1}",
926 entry
.printf_format
, target
->GetTypeInfo());
929 LLDB_LOGF(log
, "dumping ordinary printable output");
930 return target
->DumpPrintableRepresentation(s
, val_obj_display
,
934 "[Debugger::FormatPrompt] checking if I can handle as array");
935 if (!is_array
&& !is_pointer
)
937 LLDB_LOGF(log
, "[Debugger::FormatPrompt] handle as array");
938 StreamString special_directions_stream
;
939 llvm::StringRef special_directions
;
940 if (close_bracket_index
!= llvm::StringRef::npos
&&
941 subpath
.size() > close_bracket_index
) {
942 ConstString
additional_data(subpath
.drop_front(close_bracket_index
+ 1));
943 special_directions_stream
.Printf("${%svar%s", do_deref_pointer
? "*" : "",
944 additional_data
.GetCString());
946 if (entry
.fmt
!= eFormatDefault
) {
947 const char format_char
=
948 FormatManager::GetFormatAsFormatChar(entry
.fmt
);
949 if (format_char
!= '\0')
950 special_directions_stream
.Printf("%%%c", format_char
);
952 const char *format_cstr
=
953 FormatManager::GetFormatAsCString(entry
.fmt
);
954 special_directions_stream
.Printf("%%%s", format_cstr
);
956 } else if (entry
.number
!= 0) {
957 const char style_char
= ConvertValueObjectStyleToChar(
958 (ValueObject::ValueObjectRepresentationStyle
)entry
.number
);
960 special_directions_stream
.Printf("%%%c", style_char
);
962 special_directions_stream
.PutChar('}');
964 llvm::StringRef(special_directions_stream
.GetString());
967 // let us display items index_lower thru index_higher of this array
970 if (index_higher
< 0)
971 index_higher
= valobj
->GetNumChildrenIgnoringErrors() - 1;
973 uint32_t max_num_children
=
974 target
->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
977 for (int64_t index
= index_lower
; index
<= index_higher
; ++index
) {
978 ValueObject
*item
= ExpandIndexedExpression(target
, index
, false).get();
982 "[Debugger::FormatPrompt] ERROR in getting child item at "
988 "[Debugger::FormatPrompt] special_directions for child item: %s",
989 special_directions
.data() ? special_directions
.data() : "");
992 if (special_directions
.empty()) {
993 success
&= item
->DumpPrintableRepresentation(s
, val_obj_display
,
996 success
&= FormatEntity::FormatStringRef(
997 special_directions
, s
, sc
, exe_ctx
, nullptr, item
, false, false);
1000 if (--max_num_children
== 0) {
1001 s
.PutCString(", ...");
1005 if (index
< index_higher
)
1013 static bool DumpRegister(Stream
&s
, StackFrame
*frame
, const char *reg_name
,
1016 RegisterContext
*reg_ctx
= frame
->GetRegisterContext().get();
1019 const RegisterInfo
*reg_info
= reg_ctx
->GetRegisterInfoByName(reg_name
);
1021 RegisterValue reg_value
;
1022 if (reg_ctx
->ReadRegister(reg_info
, reg_value
)) {
1023 DumpRegisterValue(reg_value
, s
, *reg_info
, false, false, format
);
1032 static bool FormatThreadExtendedInfoRecurse(
1033 const FormatEntity::Entry
&entry
,
1034 const StructuredData::ObjectSP
&thread_info_dictionary
,
1035 const SymbolContext
*sc
, const ExecutionContext
*exe_ctx
, Stream
&s
) {
1036 llvm::StringRef
path(entry
.string
);
1038 StructuredData::ObjectSP value
=
1039 thread_info_dictionary
->GetObjectForDotSeparatedPath(path
);
1042 if (value
->GetType() == eStructuredDataTypeInteger
) {
1043 const char *token_format
= "0x%4.4" PRIx64
;
1044 if (!entry
.printf_format
.empty())
1045 token_format
= entry
.printf_format
.c_str();
1046 s
.Printf(token_format
, value
->GetUnsignedIntegerValue());
1048 } else if (value
->GetType() == eStructuredDataTypeFloat
) {
1049 s
.Printf("%f", value
->GetAsFloat()->GetValue());
1051 } else if (value
->GetType() == eStructuredDataTypeString
) {
1052 s
.Format("{0}", value
->GetAsString()->GetValue());
1054 } else if (value
->GetType() == eStructuredDataTypeArray
) {
1055 if (value
->GetAsArray()->GetSize() > 0) {
1056 s
.Printf("%zu", value
->GetAsArray()->GetSize());
1059 } else if (value
->GetType() == eStructuredDataTypeDictionary
) {
1061 value
->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize());
1069 static inline bool IsToken(const char *var_name_begin
, const char *var
) {
1070 return (::strncmp(var_name_begin
, var
, strlen(var
)) == 0);
1073 /// Parses the basename out of a demangled function name
1074 /// that may include function arguments. Supports
1075 /// template functions.
1077 /// Returns pointers to the opening and closing parenthesis of
1078 /// `full_name`. Can return nullptr for either parenthesis if
1080 static std::pair
<char const *, char const *>
1081 ParseBaseName(char const *full_name
) {
1082 const char *open_paren
= strchr(full_name
, '(');
1083 const char *close_paren
= nullptr;
1084 const char *generic
= strchr(full_name
, '<');
1085 // if before the arguments list begins there is a template sign
1086 // then scan to the end of the generic args before you try to find
1087 // the arguments list
1088 if (generic
&& open_paren
&& generic
< open_paren
) {
1089 int generic_depth
= 1;
1091 for (; *generic
&& generic_depth
> 0; generic
++) {
1092 if (*generic
== '<')
1094 if (*generic
== '>')
1098 open_paren
= strchr(generic
, '(');
1100 open_paren
= nullptr;
1104 if (IsToken(open_paren
, "(anonymous namespace)")) {
1105 open_paren
= strchr(open_paren
+ strlen("(anonymous namespace)"), '(');
1107 close_paren
= strchr(open_paren
, ')');
1109 close_paren
= strchr(open_paren
, ')');
1112 return {open_paren
, close_paren
};
1115 /// Writes out the function name in 'full_name' to 'out_stream'
1116 /// but replaces each argument type with the variable name
1117 /// and the corresponding pretty-printed value
1118 static void PrettyPrintFunctionNameWithArgs(Stream
&out_stream
,
1119 char const *full_name
,
1120 ExecutionContextScope
*exe_scope
,
1121 VariableList
const &args
) {
1122 auto [open_paren
, close_paren
] = ParseBaseName(full_name
);
1124 out_stream
.Write(full_name
, open_paren
- full_name
+ 1);
1126 out_stream
.PutCString(full_name
);
1127 out_stream
.PutChar('(');
1130 FormatEntity::PrettyPrintFunctionArguments(out_stream
, args
, exe_scope
);
1133 out_stream
.PutCString(close_paren
);
1135 out_stream
.PutChar(')');
1138 static void FormatInlinedBlock(Stream
&out_stream
, Block
*block
) {
1141 Block
*inline_block
= block
->GetContainingInlinedBlock();
1143 if (const InlineFunctionInfo
*inline_info
=
1144 inline_block
->GetInlinedFunctionInfo()) {
1145 out_stream
.PutCString(" [inlined] ");
1146 inline_info
->GetName().Dump(&out_stream
);
1151 bool FormatEntity::FormatStringRef(const llvm::StringRef
&format_str
, Stream
&s
,
1152 const SymbolContext
*sc
,
1153 const ExecutionContext
*exe_ctx
,
1154 const Address
*addr
, ValueObject
*valobj
,
1155 bool function_changed
,
1156 bool initial_function
) {
1157 if (!format_str
.empty()) {
1158 FormatEntity::Entry root
;
1159 Status error
= FormatEntity::Parse(format_str
, root
);
1160 if (error
.Success()) {
1161 return FormatEntity::Format(root
, s
, sc
, exe_ctx
, addr
, valobj
,
1162 function_changed
, initial_function
);
1168 bool FormatEntity::FormatCString(const char *format
, Stream
&s
,
1169 const SymbolContext
*sc
,
1170 const ExecutionContext
*exe_ctx
,
1171 const Address
*addr
, ValueObject
*valobj
,
1172 bool function_changed
, bool initial_function
) {
1173 if (format
&& format
[0]) {
1174 FormatEntity::Entry root
;
1175 llvm::StringRef
format_str(format
);
1176 Status error
= FormatEntity::Parse(format_str
, root
);
1177 if (error
.Success()) {
1178 return FormatEntity::Format(root
, s
, sc
, exe_ctx
, addr
, valobj
,
1179 function_changed
, initial_function
);
1185 bool FormatEntity::Format(const Entry
&entry
, Stream
&s
,
1186 const SymbolContext
*sc
,
1187 const ExecutionContext
*exe_ctx
, const Address
*addr
,
1188 ValueObject
*valobj
, bool function_changed
,
1189 bool initial_function
) {
1190 switch (entry
.type
) {
1191 case Entry::Type::Invalid
:
1192 case Entry::Type::ParentNumber
: // Only used for
1193 // FormatEntity::Entry::Definition encoding
1194 case Entry::Type::ParentString
: // Only used for
1195 // FormatEntity::Entry::Definition encoding
1197 case Entry::Type::EscapeCode
:
1199 if (Target
*target
= exe_ctx
->GetTargetPtr()) {
1200 Debugger
&debugger
= target
->GetDebugger();
1201 if (debugger
.GetUseColor()) {
1202 s
.PutCString(entry
.string
);
1206 // Always return true, so colors being disabled is transparent.
1209 case Entry::Type::Root
:
1210 for (const auto &child
: entry
.children
) {
1211 if (!Format(child
, s
, sc
, exe_ctx
, addr
, valobj
, function_changed
,
1212 initial_function
)) {
1213 return false; // If any item of root fails, then the formatting fails
1216 return true; // Only return true if all items succeeded
1218 case Entry::Type::String
:
1219 s
.PutCString(entry
.string
);
1222 case Entry::Type::Scope
: {
1223 StreamString scope_stream
;
1224 bool success
= false;
1225 for (const auto &child
: entry
.children
) {
1226 success
= Format(child
, scope_stream
, sc
, exe_ctx
, addr
, valobj
,
1227 function_changed
, initial_function
);
1231 // Only if all items in a scope succeed, then do we print the output into
1234 s
.Write(scope_stream
.GetString().data(), scope_stream
.GetString().size());
1236 return true; // Scopes always successfully print themselves
1238 case Entry::Type::Variable
:
1239 case Entry::Type::VariableSynthetic
:
1240 case Entry::Type::ScriptVariable
:
1241 case Entry::Type::ScriptVariableSynthetic
:
1242 return DumpValue(s
, sc
, exe_ctx
, entry
, valobj
);
1244 case Entry::Type::AddressFile
:
1245 case Entry::Type::AddressLoad
:
1246 case Entry::Type::AddressLoadOrFile
:
1248 addr
!= nullptr && addr
->IsValid() &&
1249 DumpAddressAndContent(s
, sc
, exe_ctx
, *addr
,
1250 entry
.type
== Entry::Type::AddressLoadOrFile
));
1252 case Entry::Type::ProcessID
:
1254 Process
*process
= exe_ctx
->GetProcessPtr();
1256 const char *format
= "%" PRIu64
;
1257 if (!entry
.printf_format
.empty())
1258 format
= entry
.printf_format
.c_str();
1259 s
.Printf(format
, process
->GetID());
1265 case Entry::Type::ProcessFile
:
1267 Process
*process
= exe_ctx
->GetProcessPtr();
1269 Module
*exe_module
= process
->GetTarget().GetExecutableModulePointer();
1271 if (DumpFile(s
, exe_module
->GetFileSpec(), (FileKind
)entry
.number
))
1278 case Entry::Type::ScriptProcess
:
1280 Process
*process
= exe_ctx
->GetProcessPtr();
1282 return RunScriptFormatKeyword(s
, sc
, exe_ctx
, process
,
1283 entry
.string
.c_str());
1287 case Entry::Type::ThreadID
:
1289 Thread
*thread
= exe_ctx
->GetThreadPtr();
1291 const char *format
= "0x%4.4" PRIx64
;
1292 if (!entry
.printf_format
.empty()) {
1293 // Watch for the special "tid" format...
1294 if (entry
.printf_format
== "tid") {
1295 // TODO(zturner): Rather than hardcoding this to be platform
1296 // specific, it should be controlled by a setting and the default
1297 // value of the setting can be different depending on the platform.
1298 Target
&target
= thread
->GetProcess()->GetTarget();
1299 ArchSpec
arch(target
.GetArchitecture());
1300 llvm::Triple::OSType ostype
= arch
.IsValid()
1301 ? arch
.GetTriple().getOS()
1302 : llvm::Triple::UnknownOS
;
1303 if (ostype
== llvm::Triple::FreeBSD
||
1304 ostype
== llvm::Triple::Linux
||
1305 ostype
== llvm::Triple::NetBSD
||
1306 ostype
== llvm::Triple::OpenBSD
) {
1307 format
= "%" PRIu64
;
1310 format
= entry
.printf_format
.c_str();
1313 s
.Printf(format
, thread
->GetID());
1319 case Entry::Type::ThreadProtocolID
:
1321 Thread
*thread
= exe_ctx
->GetThreadPtr();
1323 const char *format
= "0x%4.4" PRIx64
;
1324 if (!entry
.printf_format
.empty())
1325 format
= entry
.printf_format
.c_str();
1326 s
.Printf(format
, thread
->GetProtocolID());
1332 case Entry::Type::ThreadIndexID
:
1334 Thread
*thread
= exe_ctx
->GetThreadPtr();
1336 const char *format
= "%" PRIu32
;
1337 if (!entry
.printf_format
.empty())
1338 format
= entry
.printf_format
.c_str();
1339 s
.Printf(format
, thread
->GetIndexID());
1345 case Entry::Type::ThreadName
:
1347 Thread
*thread
= exe_ctx
->GetThreadPtr();
1349 const char *cstr
= thread
->GetName();
1350 if (cstr
&& cstr
[0]) {
1358 case Entry::Type::ThreadQueue
:
1360 Thread
*thread
= exe_ctx
->GetThreadPtr();
1362 const char *cstr
= thread
->GetQueueName();
1363 if (cstr
&& cstr
[0]) {
1371 case Entry::Type::ThreadStopReason
:
1373 if (Thread
*thread
= exe_ctx
->GetThreadPtr()) {
1374 std::string stop_description
= thread
->GetStopDescription();
1375 if (!stop_description
.empty()) {
1376 s
.PutCString(stop_description
);
1383 case Entry::Type::ThreadStopReasonRaw
:
1385 if (Thread
*thread
= exe_ctx
->GetThreadPtr()) {
1386 std::string stop_description
= thread
->GetStopDescriptionRaw();
1387 if (!stop_description
.empty()) {
1388 s
.PutCString(stop_description
);
1395 case Entry::Type::ThreadReturnValue
:
1397 Thread
*thread
= exe_ctx
->GetThreadPtr();
1399 StopInfoSP stop_info_sp
= thread
->GetStopInfo();
1400 if (stop_info_sp
&& stop_info_sp
->IsValid()) {
1401 ValueObjectSP return_valobj_sp
=
1402 StopInfo::GetReturnValueObject(stop_info_sp
);
1403 if (return_valobj_sp
) {
1404 if (llvm::Error error
= return_valobj_sp
->Dump(s
)) {
1405 s
<< "error: " << toString(std::move(error
));
1415 case Entry::Type::ThreadCompletedExpression
:
1417 Thread
*thread
= exe_ctx
->GetThreadPtr();
1419 StopInfoSP stop_info_sp
= thread
->GetStopInfo();
1420 if (stop_info_sp
&& stop_info_sp
->IsValid()) {
1421 ExpressionVariableSP expression_var_sp
=
1422 StopInfo::GetExpressionVariable(stop_info_sp
);
1423 if (expression_var_sp
&& expression_var_sp
->GetValueObject()) {
1424 if (llvm::Error error
=
1425 expression_var_sp
->GetValueObject()->Dump(s
)) {
1426 s
<< "error: " << toString(std::move(error
));
1436 case Entry::Type::ScriptThread
:
1438 Thread
*thread
= exe_ctx
->GetThreadPtr();
1440 return RunScriptFormatKeyword(s
, sc
, exe_ctx
, thread
,
1441 entry
.string
.c_str());
1445 case Entry::Type::ThreadInfo
:
1447 Thread
*thread
= exe_ctx
->GetThreadPtr();
1449 StructuredData::ObjectSP object_sp
= thread
->GetExtendedInfo();
1451 object_sp
->GetType() == eStructuredDataTypeDictionary
) {
1452 if (FormatThreadExtendedInfoRecurse(entry
, object_sp
, sc
, exe_ctx
, s
))
1459 case Entry::Type::TargetArch
:
1461 Target
*target
= exe_ctx
->GetTargetPtr();
1463 const ArchSpec
&arch
= target
->GetArchitecture();
1464 if (arch
.IsValid()) {
1465 s
.PutCString(arch
.GetArchitectureName());
1472 case Entry::Type::ScriptTarget
:
1474 Target
*target
= exe_ctx
->GetTargetPtr();
1476 return RunScriptFormatKeyword(s
, sc
, exe_ctx
, target
,
1477 entry
.string
.c_str());
1481 case Entry::Type::ModuleFile
:
1483 Module
*module
= sc
->module_sp
.get();
1485 if (DumpFile(s
, module
->GetFileSpec(), (FileKind
)entry
.number
))
1491 case Entry::Type::File
:
1493 CompileUnit
*cu
= sc
->comp_unit
;
1495 if (DumpFile(s
, cu
->GetPrimaryFile(), (FileKind
)entry
.number
))
1501 case Entry::Type::Lang
:
1503 CompileUnit
*cu
= sc
->comp_unit
;
1505 const char *lang_name
=
1506 Language::GetNameForLanguageType(cu
->GetLanguage());
1508 s
.PutCString(lang_name
);
1515 case Entry::Type::FrameIndex
:
1517 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1519 const char *format
= "%" PRIu32
;
1520 if (!entry
.printf_format
.empty())
1521 format
= entry
.printf_format
.c_str();
1522 s
.Printf(format
, frame
->GetFrameIndex());
1528 case Entry::Type::FrameRegisterPC
:
1530 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1532 const Address
&pc_addr
= frame
->GetFrameCodeAddress();
1533 if (pc_addr
.IsValid()) {
1534 if (DumpAddressAndContent(s
, sc
, exe_ctx
, pc_addr
, false))
1541 case Entry::Type::FrameRegisterSP
:
1543 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1545 if (DumpRegister(s
, frame
, eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_SP
,
1546 (lldb::Format
)entry
.number
))
1552 case Entry::Type::FrameRegisterFP
:
1554 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1556 if (DumpRegister(s
, frame
, eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_FP
,
1557 (lldb::Format
)entry
.number
))
1563 case Entry::Type::FrameRegisterFlags
:
1565 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1567 if (DumpRegister(s
, frame
, eRegisterKindGeneric
,
1568 LLDB_REGNUM_GENERIC_FLAGS
, (lldb::Format
)entry
.number
))
1574 case Entry::Type::FrameNoDebug
:
1576 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1578 return !frame
->HasDebugInformation();
1583 case Entry::Type::FrameRegisterByName
:
1585 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1587 if (DumpRegister(s
, frame
, entry
.string
.c_str(),
1588 (lldb::Format
)entry
.number
))
1594 case Entry::Type::FrameIsArtificial
: {
1596 if (StackFrame
*frame
= exe_ctx
->GetFramePtr())
1597 return frame
->IsArtificial();
1601 case Entry::Type::ScriptFrame
:
1603 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1605 return RunScriptFormatKeyword(s
, sc
, exe_ctx
, frame
,
1606 entry
.string
.c_str());
1610 case Entry::Type::FunctionID
:
1613 s
.Printf("function{0x%8.8" PRIx64
"}", sc
->function
->GetID());
1615 } else if (sc
->symbol
) {
1616 s
.Printf("symbol[%u]", sc
->symbol
->GetID());
1622 case Entry::Type::FunctionDidChange
:
1623 return function_changed
;
1625 case Entry::Type::FunctionInitialFunction
:
1626 return initial_function
;
1628 case Entry::Type::FunctionName
: {
1632 Language
*language_plugin
= nullptr;
1633 bool language_plugin_handled
= false;
1637 language_plugin
= Language::FindPlugin(sc
->function
->GetLanguage());
1638 else if (sc
->symbol
)
1639 language_plugin
= Language::FindPlugin(sc
->symbol
->GetLanguage());
1641 if (language_plugin
)
1642 language_plugin_handled
= language_plugin
->GetFunctionDisplayName(
1643 sc
, exe_ctx
, Language::FunctionNameRepresentation::eName
, ss
);
1645 if (language_plugin_handled
) {
1646 s
<< ss
.GetString();
1649 const char *name
= nullptr;
1651 name
= sc
->function
->GetName().AsCString(nullptr);
1652 else if (sc
->symbol
)
1653 name
= sc
->symbol
->GetName().AsCString(nullptr);
1657 FormatInlinedBlock(s
, sc
->block
);
1664 case Entry::Type::FunctionNameNoArgs
: {
1668 Language
*language_plugin
= nullptr;
1669 bool language_plugin_handled
= false;
1672 language_plugin
= Language::FindPlugin(sc
->function
->GetLanguage());
1673 else if (sc
->symbol
)
1674 language_plugin
= Language::FindPlugin(sc
->symbol
->GetLanguage());
1676 if (language_plugin
)
1677 language_plugin_handled
= language_plugin
->GetFunctionDisplayName(
1678 sc
, exe_ctx
, Language::FunctionNameRepresentation::eNameWithNoArgs
,
1681 if (language_plugin_handled
) {
1682 s
<< ss
.GetString();
1687 name
= sc
->function
->GetNameNoArguments();
1688 else if (sc
->symbol
)
1689 name
= sc
->symbol
->GetNameNoArguments();
1691 s
.PutCString(name
.GetCString());
1692 FormatInlinedBlock(s
, sc
->block
);
1699 case Entry::Type::FunctionNameWithArgs
: {
1703 Language
*language_plugin
= nullptr;
1704 bool language_plugin_handled
= false;
1707 language_plugin
= Language::FindPlugin(sc
->function
->GetLanguage());
1708 else if (sc
->symbol
)
1709 language_plugin
= Language::FindPlugin(sc
->symbol
->GetLanguage());
1711 if (language_plugin
)
1712 language_plugin_handled
= language_plugin
->GetFunctionDisplayName(
1713 sc
, exe_ctx
, Language::FunctionNameRepresentation::eNameWithArgs
, ss
);
1715 if (language_plugin_handled
) {
1716 s
<< ss
.GetString();
1719 // Print the function name with arguments in it
1721 ExecutionContextScope
*exe_scope
=
1722 exe_ctx
? exe_ctx
->GetBestExecutionContextScope() : nullptr;
1723 const char *cstr
= sc
->function
->GetName().AsCString(nullptr);
1725 const InlineFunctionInfo
*inline_info
= nullptr;
1726 VariableListSP variable_list_sp
;
1727 bool get_function_vars
= true;
1729 Block
*inline_block
= sc
->block
->GetContainingInlinedBlock();
1732 get_function_vars
= false;
1733 inline_info
= inline_block
->GetInlinedFunctionInfo();
1735 variable_list_sp
= inline_block
->GetBlockVariableList(true);
1739 if (get_function_vars
) {
1741 sc
->function
->GetBlock(true).GetBlockVariableList(true);
1746 s
.PutCString(" [inlined] ");
1747 cstr
= inline_info
->GetName().GetCString();
1751 if (variable_list_sp
)
1752 variable_list_sp
->AppendVariablesWithScope(
1753 eValueTypeVariableArgument
, args
);
1754 if (args
.GetSize() > 0) {
1755 PrettyPrintFunctionNameWithArgs(s
, cstr
, exe_scope
, args
);
1761 } else if (sc
->symbol
) {
1762 const char *cstr
= sc
->symbol
->GetName().AsCString(nullptr);
1772 case Entry::Type::FunctionMangledName
: {
1776 const char *name
= nullptr;
1779 sc
->symbol
->GetMangled().GetName(Mangled::ePreferMangled
).AsCString();
1780 else if (sc
->function
)
1781 name
= sc
->function
->GetMangled()
1782 .GetName(Mangled::ePreferMangled
)
1788 FormatInlinedBlock(s
, sc
->block
);
1791 case Entry::Type::FunctionAddrOffset
:
1793 if (DumpAddressOffsetFromFunction(s
, sc
, exe_ctx
, *addr
, false, false,
1799 case Entry::Type::FunctionAddrOffsetConcrete
:
1801 if (DumpAddressOffsetFromFunction(s
, sc
, exe_ctx
, *addr
, true, true,
1807 case Entry::Type::FunctionLineOffset
:
1809 return (DumpAddressOffsetFromFunction(
1810 s
, sc
, exe_ctx
, sc
->line_entry
.range
.GetBaseAddress(), false, false,
1814 case Entry::Type::FunctionPCOffset
:
1816 StackFrame
*frame
= exe_ctx
->GetFramePtr();
1818 if (DumpAddressOffsetFromFunction(s
, sc
, exe_ctx
,
1819 frame
->GetFrameCodeAddress(), false,
1826 case Entry::Type::FunctionChanged
:
1827 return function_changed
;
1829 case Entry::Type::FunctionIsOptimized
: {
1830 bool is_optimized
= false;
1831 if (sc
&& sc
->function
&& sc
->function
->GetIsOptimized()) {
1832 is_optimized
= true;
1834 return is_optimized
;
1837 case Entry::Type::FunctionInitial
:
1838 return initial_function
;
1840 case Entry::Type::LineEntryFile
:
1841 if (sc
&& sc
->line_entry
.IsValid()) {
1842 Module
*module
= sc
->module_sp
.get();
1844 if (DumpFile(s
, sc
->line_entry
.GetFile(), (FileKind
)entry
.number
))
1850 case Entry::Type::LineEntryLineNumber
:
1851 if (sc
&& sc
->line_entry
.IsValid()) {
1852 const char *format
= "%" PRIu32
;
1853 if (!entry
.printf_format
.empty())
1854 format
= entry
.printf_format
.c_str();
1855 s
.Printf(format
, sc
->line_entry
.line
);
1860 case Entry::Type::LineEntryColumn
:
1861 if (sc
&& sc
->line_entry
.IsValid() && sc
->line_entry
.column
) {
1862 const char *format
= "%" PRIu32
;
1863 if (!entry
.printf_format
.empty())
1864 format
= entry
.printf_format
.c_str();
1865 s
.Printf(format
, sc
->line_entry
.column
);
1870 case Entry::Type::LineEntryStartAddress
:
1871 case Entry::Type::LineEntryEndAddress
:
1872 if (sc
&& sc
->line_entry
.range
.GetBaseAddress().IsValid()) {
1873 Address addr
= sc
->line_entry
.range
.GetBaseAddress();
1875 if (entry
.type
== Entry::Type::LineEntryEndAddress
)
1876 addr
.Slide(sc
->line_entry
.range
.GetByteSize());
1877 if (DumpAddressAndContent(s
, sc
, exe_ctx
, addr
, false))
1882 case Entry::Type::CurrentPCArrow
:
1883 if (addr
&& exe_ctx
&& exe_ctx
->GetFramePtr()) {
1884 RegisterContextSP reg_ctx
=
1885 exe_ctx
->GetFramePtr()->GetRegisterContextSP();
1887 addr_t pc_loadaddr
= reg_ctx
->GetPC();
1888 if (pc_loadaddr
!= LLDB_INVALID_ADDRESS
) {
1890 pc
.SetLoadAddress(pc_loadaddr
, exe_ctx
->GetTargetPtr());
1905 static bool DumpCommaSeparatedChildEntryNames(Stream
&s
,
1906 const Definition
*parent
) {
1907 if (parent
->children
) {
1908 const size_t n
= parent
->num_children
;
1909 for (size_t i
= 0; i
< n
; ++i
) {
1912 s
.Printf("\"%s\"", parent
->children
[i
].name
);
1919 static Status
ParseEntry(const llvm::StringRef
&format_str
,
1920 const Definition
*parent
, FormatEntity::Entry
&entry
) {
1923 const size_t sep_pos
= format_str
.find_first_of(".[:");
1924 const char sep_char
=
1925 (sep_pos
== llvm::StringRef::npos
) ? '\0' : format_str
[sep_pos
];
1926 llvm::StringRef key
= format_str
.substr(0, sep_pos
);
1928 const size_t n
= parent
->num_children
;
1929 for (size_t i
= 0; i
< n
; ++i
) {
1930 const Definition
*entry_def
= parent
->children
+ i
;
1931 if (key
== entry_def
->name
|| entry_def
->name
[0] == '*') {
1932 llvm::StringRef value
;
1935 format_str
.substr(sep_pos
+ (entry_def
->keep_separator
? 0 : 1));
1936 switch (entry_def
->type
) {
1937 case FormatEntity::Entry::Type::ParentString
:
1938 entry
.string
= format_str
.str();
1939 return error
; // Success
1941 case FormatEntity::Entry::Type::ParentNumber
:
1942 entry
.number
= entry_def
->data
;
1943 return error
; // Success
1945 case FormatEntity::Entry::Type::EscapeCode
:
1946 entry
.type
= entry_def
->type
;
1947 entry
.string
= entry_def
->string
;
1948 return error
; // Success
1951 entry
.type
= entry_def
->type
;
1955 if (value
.empty()) {
1956 if (entry_def
->type
== FormatEntity::Entry::Type::Invalid
) {
1957 if (entry_def
->children
) {
1958 StreamString error_strm
;
1959 error_strm
.Printf("'%s' can't be specified on its own, you must "
1960 "access one of its children: ",
1962 DumpCommaSeparatedChildEntryNames(error_strm
, entry_def
);
1964 Status::FromErrorStringWithFormat("%s", error_strm
.GetData());
1965 } else if (sep_char
== ':') {
1966 // Any value whose separator is a with a ':' means this value has a
1967 // string argument that needs to be stored in the entry (like
1968 // "${script.var:}"). In this case the string value is the empty
1969 // string which is ok.
1971 error
= Status::FromErrorStringWithFormat(
1972 "%s", "invalid entry definitions");
1976 if (entry_def
->children
) {
1977 error
= ParseEntry(value
, entry_def
, entry
);
1978 } else if (sep_char
== ':') {
1979 // Any value whose separator is a with a ':' means this value has a
1980 // string argument that needs to be stored in the entry (like
1981 // "${script.var:modulename.function}")
1982 entry
.string
= value
.str();
1984 error
= Status::FromErrorStringWithFormat(
1985 "'%s' followed by '%s' but it has no children", key
.str().c_str(),
1986 value
.str().c_str());
1992 StreamString error_strm
;
1993 if (parent
->type
== FormatEntity::Entry::Type::Root
)
1995 "invalid top level item '%s'. Valid top level items are: ",
1998 error_strm
.Printf("invalid member '%s' in '%s'. Valid members are: ",
1999 key
.str().c_str(), parent
->name
);
2000 DumpCommaSeparatedChildEntryNames(error_strm
, parent
);
2001 error
= Status::FromErrorStringWithFormat("%s", error_strm
.GetData());
2005 static const Definition
*FindEntry(const llvm::StringRef
&format_str
,
2006 const Definition
*parent
,
2007 llvm::StringRef
&remainder
) {
2010 std::pair
<llvm::StringRef
, llvm::StringRef
> p
= format_str
.split('.');
2011 const size_t n
= parent
->num_children
;
2012 for (size_t i
= 0; i
< n
; ++i
) {
2013 const Definition
*entry_def
= parent
->children
+ i
;
2014 if (p
.first
== entry_def
->name
|| entry_def
->name
[0] == '*') {
2015 if (p
.second
.empty()) {
2016 if (format_str
.back() == '.')
2017 remainder
= format_str
.drop_front(format_str
.size() - 1);
2019 remainder
= llvm::StringRef(); // Exact match
2022 if (entry_def
->children
) {
2023 return FindEntry(p
.second
, entry_def
, remainder
);
2025 remainder
= p
.second
;
2031 remainder
= format_str
;
2035 static Status
ParseInternal(llvm::StringRef
&format
, Entry
&parent_entry
,
2038 while (!format
.empty() && error
.Success()) {
2039 const size_t non_special_chars
= format
.find_first_of("${}\\");
2041 if (non_special_chars
== llvm::StringRef::npos
) {
2042 // No special characters, just string bytes so add them and we are done
2043 parent_entry
.AppendText(format
);
2047 if (non_special_chars
> 0) {
2048 // We have a special character, so add all characters before these as a
2050 parent_entry
.AppendText(format
.substr(0, non_special_chars
));
2051 format
= format
.drop_front(non_special_chars
);
2054 switch (format
[0]) {
2059 format
= format
.drop_front(); // Skip the '{'
2060 Entry
scope_entry(Entry::Type::Scope
);
2061 error
= ParseInternal(format
, scope_entry
, depth
+ 1);
2064 parent_entry
.AppendEntry(std::move(scope_entry
));
2069 error
= Status::FromErrorString("unmatched '}' character");
2073 .drop_front(); // Skip the '}' as we are at the end of the scope
2077 format
= format
.drop_front(); // Skip the '\' character
2078 if (format
.empty()) {
2079 error
= Status::FromErrorString(
2080 "'\\' character was not followed by another character");
2084 const char desens_char
= format
[0];
2085 format
= format
.drop_front(); // Skip the desensitized char character
2086 switch (desens_char
) {
2088 parent_entry
.AppendChar('\a');
2091 parent_entry
.AppendChar('\b');
2094 parent_entry
.AppendChar('\f');
2097 parent_entry
.AppendChar('\n');
2100 parent_entry
.AppendChar('\r');
2103 parent_entry
.AppendChar('\t');
2106 parent_entry
.AppendChar('\v');
2109 parent_entry
.AppendChar('\'');
2112 parent_entry
.AppendChar('\\');
2115 // 1 to 3 octal chars
2117 // Make a string that can hold onto the initial zero char, up to 3
2118 // octal digits, and a terminating NULL.
2119 char oct_str
[5] = {0, 0, 0, 0, 0};
2122 for (i
= 0; (format
[i
] >= '0' && format
[i
] <= '7') && i
< 4; ++i
)
2123 oct_str
[i
] = format
[i
];
2125 // We don't want to consume the last octal character since the main
2126 // for loop will do this for us, so we advance p by one less than i
2127 // (even if i is zero)
2128 format
= format
.drop_front(i
);
2129 unsigned long octal_value
= ::strtoul(oct_str
, nullptr, 8);
2130 if (octal_value
<= UINT8_MAX
) {
2131 parent_entry
.AppendChar((char)octal_value
);
2133 error
= Status::FromErrorString(
2134 "octal number is larger than a single byte");
2141 // hex number in the format
2142 if (isxdigit(format
[0])) {
2143 // Make a string that can hold onto two hex chars plus a
2145 char hex_str
[3] = {0, 0, 0};
2146 hex_str
[0] = format
[0];
2148 format
= format
.drop_front();
2150 if (isxdigit(format
[0])) {
2151 hex_str
[1] = format
[0];
2152 format
= format
.drop_front();
2155 unsigned long hex_value
= strtoul(hex_str
, nullptr, 16);
2156 if (hex_value
<= UINT8_MAX
) {
2157 parent_entry
.AppendChar((char)hex_value
);
2159 error
= Status::FromErrorString(
2160 "hex number is larger than a single byte");
2164 parent_entry
.AppendChar(desens_char
);
2169 // Just desensitize any other character by just printing what came
2171 parent_entry
.AppendChar(desens_char
);
2177 format
= format
.drop_front(); // Skip the '$'
2178 if (format
.empty() || format
.front() != '{') {
2179 // Print '$' when not followed by '{'.
2180 parent_entry
.AppendText("$");
2182 format
= format
.drop_front(); // Skip the '{'
2184 llvm::StringRef variable
, variable_format
;
2185 error
= FormatEntity::ExtractVariableInfo(format
, variable
,
2189 bool verify_is_thread_id
= false;
2191 if (!variable_format
.empty()) {
2192 entry
.printf_format
= variable_format
.str();
2194 // If the format contains a '%' we are going to assume this is a
2195 // printf style format. So if you want to format your thread ID
2196 // using "0x%llx" you can use: ${thread.id%0x%llx}
2198 // If there is no '%' in the format, then it is assumed to be a
2199 // LLDB format name, or one of the extended formats specified in
2200 // the switch statement below.
2202 if (entry
.printf_format
.find('%') == std::string::npos
) {
2203 bool clear_printf
= false;
2205 if (entry
.printf_format
.size() == 1) {
2206 switch (entry
.printf_format
[0]) {
2207 case '@': // if this is an @ sign, print ObjC description
2208 entry
.number
= ValueObject::
2209 eValueObjectRepresentationStyleLanguageSpecific
;
2210 clear_printf
= true;
2212 case 'V': // if this is a V, print the value using the default
2215 ValueObject::eValueObjectRepresentationStyleValue
;
2216 clear_printf
= true;
2218 case 'L': // if this is an L, print the location of the value
2220 ValueObject::eValueObjectRepresentationStyleLocation
;
2221 clear_printf
= true;
2223 case 'S': // if this is an S, print the summary after all
2225 ValueObject::eValueObjectRepresentationStyleSummary
;
2226 clear_printf
= true;
2228 case '#': // if this is a '#', print the number of children
2230 ValueObject::eValueObjectRepresentationStyleChildrenCount
;
2231 clear_printf
= true;
2233 case 'T': // if this is a 'T', print the type
2234 entry
.number
= ValueObject::eValueObjectRepresentationStyleType
;
2235 clear_printf
= true;
2237 case 'N': // if this is a 'N', print the name
2238 entry
.number
= ValueObject::eValueObjectRepresentationStyleName
;
2239 clear_printf
= true;
2241 case '>': // if this is a '>', print the expression path
2243 ValueObject::eValueObjectRepresentationStyleExpressionPath
;
2244 clear_printf
= true;
2249 if (entry
.number
== 0) {
2250 if (FormatManager::GetFormatFromCString(
2251 entry
.printf_format
.c_str(), entry
.fmt
)) {
2252 clear_printf
= true;
2253 } else if (entry
.printf_format
== "tid") {
2254 verify_is_thread_id
= true;
2256 error
= Status::FromErrorStringWithFormat(
2257 "invalid format: '%s'", entry
.printf_format
.c_str());
2262 // Our format string turned out to not be a printf style format
2263 // so lets clear the string
2265 entry
.printf_format
.clear();
2269 // Check for dereferences
2270 if (variable
[0] == '*') {
2272 variable
= variable
.drop_front();
2275 error
= ParseEntry(variable
, &g_root
, entry
);
2279 llvm::StringRef
entry_string(entry
.string
);
2280 if (entry_string
.contains(':')) {
2281 auto [_
, llvm_format
] = entry_string
.split(':');
2282 if (!llvm_format
.empty() && !LLVMFormatPattern
.match(llvm_format
)) {
2283 error
= Status::FromErrorStringWithFormat(
2284 "invalid llvm format: '%s'", llvm_format
.data());
2289 if (verify_is_thread_id
) {
2290 if (entry
.type
!= Entry::Type::ThreadID
&&
2291 entry
.type
!= Entry::Type::ThreadProtocolID
) {
2292 error
= Status::FromErrorString(
2293 "the 'tid' format can only be used on "
2294 "${thread.id} and ${thread.protocol_id}");
2298 switch (entry
.type
) {
2299 case Entry::Type::Variable
:
2300 case Entry::Type::VariableSynthetic
:
2301 if (entry
.number
== 0) {
2302 if (entry
.string
.empty())
2303 entry
.number
= ValueObject::eValueObjectRepresentationStyleValue
;
2306 ValueObject::eValueObjectRepresentationStyleSummary
;
2310 // Make sure someone didn't try to dereference anything but ${var}
2313 error
= Status::FromErrorStringWithFormat(
2314 "${%s} can't be dereferenced, only ${var} and ${svar} can.",
2315 variable
.str().c_str());
2319 parent_entry
.AppendEntry(std::move(entry
));
2327 Status
FormatEntity::ExtractVariableInfo(llvm::StringRef
&format_str
,
2328 llvm::StringRef
&variable_name
,
2329 llvm::StringRef
&variable_format
) {
2331 variable_name
= llvm::StringRef();
2332 variable_format
= llvm::StringRef();
2334 const size_t paren_pos
= format_str
.find('}');
2335 if (paren_pos
!= llvm::StringRef::npos
) {
2336 const size_t percent_pos
= format_str
.find('%');
2337 if (percent_pos
< paren_pos
) {
2338 if (percent_pos
> 0) {
2339 if (percent_pos
> 1)
2340 variable_name
= format_str
.substr(0, percent_pos
);
2342 format_str
.substr(percent_pos
+ 1, paren_pos
- (percent_pos
+ 1));
2345 variable_name
= format_str
.substr(0, paren_pos
);
2347 // Strip off elements and the formatting and the trailing '}'
2348 format_str
= format_str
.substr(paren_pos
+ 1);
2350 error
= Status::FromErrorStringWithFormat(
2351 "missing terminating '}' character for '${%s'",
2352 format_str
.str().c_str());
2357 bool FormatEntity::FormatFileSpec(const FileSpec
&file_spec
, Stream
&s
,
2358 llvm::StringRef variable_name
,
2359 llvm::StringRef variable_format
) {
2360 if (variable_name
.empty() || variable_name
== ".fullpath") {
2361 file_spec
.Dump(s
.AsRawOstream());
2363 } else if (variable_name
== ".basename") {
2364 s
.PutCString(file_spec
.GetFilename().GetStringRef());
2366 } else if (variable_name
== ".dirname") {
2367 s
.PutCString(file_spec
.GetFilename().GetStringRef());
2373 static std::string
MakeMatch(const llvm::StringRef
&prefix
,
2374 const char *suffix
) {
2375 std::string
match(prefix
.str());
2376 match
.append(suffix
);
2380 static void AddMatches(const Definition
*def
, const llvm::StringRef
&prefix
,
2381 const llvm::StringRef
&match_prefix
,
2382 StringList
&matches
) {
2383 const size_t n
= def
->num_children
;
2385 for (size_t i
= 0; i
< n
; ++i
) {
2386 std::string match
= prefix
.str();
2387 if (match_prefix
.empty())
2388 matches
.AppendString(MakeMatch(prefix
, def
->children
[i
].name
));
2389 else if (strncmp(def
->children
[i
].name
, match_prefix
.data(),
2390 match_prefix
.size()) == 0)
2391 matches
.AppendString(
2392 MakeMatch(prefix
, def
->children
[i
].name
+ match_prefix
.size()));
2397 void FormatEntity::AutoComplete(CompletionRequest
&request
) {
2398 llvm::StringRef str
= request
.GetCursorArgumentPrefix();
2400 const size_t dollar_pos
= str
.rfind('$');
2401 if (dollar_pos
== llvm::StringRef::npos
)
2404 // Hitting TAB after $ at the end of the string add a "{"
2405 if (dollar_pos
== str
.size() - 1) {
2406 std::string match
= str
.str();
2408 request
.AddCompletion(match
);
2412 if (str
[dollar_pos
+ 1] != '{')
2415 const size_t close_pos
= str
.find('}', dollar_pos
+ 2);
2416 if (close_pos
!= llvm::StringRef::npos
)
2419 const size_t format_pos
= str
.find('%', dollar_pos
+ 2);
2420 if (format_pos
!= llvm::StringRef::npos
)
2423 llvm::StringRef
partial_variable(str
.substr(dollar_pos
+ 2));
2424 if (partial_variable
.empty()) {
2425 // Suggest all top level entities as we are just past "${"
2426 StringList new_matches
;
2427 AddMatches(&g_root
, str
, llvm::StringRef(), new_matches
);
2428 request
.AddCompletions(new_matches
);
2432 // We have a partially specified variable, find it
2433 llvm::StringRef remainder
;
2434 const Definition
*entry_def
= FindEntry(partial_variable
, &g_root
, remainder
);
2438 const size_t n
= entry_def
->num_children
;
2440 if (remainder
.empty()) {
2443 // "${thread.info" <TAB>
2444 request
.AddCompletion(MakeMatch(str
, "."));
2446 // "${thread.id" <TAB>
2447 request
.AddCompletion(MakeMatch(str
, "}"));
2449 } else if (remainder
== ".") {
2450 // "${thread." <TAB>
2451 StringList new_matches
;
2452 AddMatches(entry_def
, str
, llvm::StringRef(), new_matches
);
2453 request
.AddCompletions(new_matches
);
2455 // We have a partial match
2457 StringList new_matches
;
2458 AddMatches(entry_def
, str
, remainder
, new_matches
);
2459 request
.AddCompletions(new_matches
);
2463 void FormatEntity::PrettyPrintFunctionArguments(
2464 Stream
&out_stream
, VariableList
const &args
,
2465 ExecutionContextScope
*exe_scope
) {
2466 const size_t num_args
= args
.GetSize();
2467 for (size_t arg_idx
= 0; arg_idx
< num_args
; ++arg_idx
) {
2470 VariableSP
var_sp(args
.GetVariableAtIndex(arg_idx
));
2471 ValueObjectSP
var_value_sp(ValueObjectVariable::Create(exe_scope
, var_sp
));
2473 llvm::StringRef var_representation
;
2474 const char *var_name
= var_value_sp
->GetName().GetCString();
2475 if (var_value_sp
->GetCompilerType().IsValid()) {
2476 if (exe_scope
&& exe_scope
->CalculateTarget())
2477 var_value_sp
= var_value_sp
->GetQualifiedRepresentationIfAvailable(
2478 exe_scope
->CalculateTarget()
2479 ->TargetProperties::GetPreferDynamicValue(),
2480 exe_scope
->CalculateTarget()
2481 ->TargetProperties::GetEnableSyntheticValue());
2482 if (var_value_sp
->GetCompilerType().IsAggregateType() &&
2483 DataVisualization::ShouldPrintAsOneLiner(*var_value_sp
)) {
2484 static StringSummaryFormat
format(TypeSummaryImpl::Flags()
2485 .SetHideItemNames(false)
2486 .SetShowMembersOneLiner(true),
2488 format
.FormatObject(var_value_sp
.get(), buffer
, TypeSummaryOptions());
2489 var_representation
= buffer
;
2491 var_value_sp
->DumpPrintableRepresentation(
2493 ValueObject::ValueObjectRepresentationStyle::
2494 eValueObjectRepresentationStyleSummary
,
2496 ValueObject::PrintableRepresentationSpecialCases::eAllow
, false);
2499 if (!ss
.GetString().empty())
2500 var_representation
= ss
.GetString();
2502 out_stream
.PutCString(", ");
2503 if (var_value_sp
->GetError().Success()) {
2504 if (!var_representation
.empty())
2505 out_stream
.Printf("%s=%s", var_name
, var_representation
.str().c_str());
2507 out_stream
.Printf("%s=%s at %s", var_name
,
2508 var_value_sp
->GetTypeName().GetCString(),
2509 var_value_sp
->GetLocationAsCString());
2511 out_stream
.Printf("%s=<unavailable>", var_name
);
2515 Status
FormatEntity::Parse(const llvm::StringRef
&format_str
, Entry
&entry
) {
2517 entry
.type
= Entry::Type::Root
;
2518 llvm::StringRef
modifiable_format(format_str
);
2519 return ParseInternal(modifiable_format
, entry
, 0);