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