Bug Summary

File:tools/lldb/source/Core/FormatEntity.cpp
Warning:line 1699, column 37
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

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