Bug Summary

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

Annotated Source Code

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