Bug Summary

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