Skip to content

Commit d8060f8

Browse files
author
walter erquinigo
committed
[lldb-vscode] Show value addresses in a short format
The variables pane on VSCode is very narrow by default, and lldb-vscode has been using the default formatter for addresses, which uses 18 characters for each address. That's a bit too much because it prints too many leading zeroes. As a way to improve readability of variables, I'm adding some logic to format addresses manually using as few chars as possible. I don't want to mess with the default LLDB formatter because, if the user uses the debug console, they should see addresses formatted in the regular way.
1 parent 4a030f5 commit d8060f8

File tree

6 files changed

+127
-17
lines changed

6 files changed

+127
-17
lines changed

lldb/include/lldb/API/SBType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ class SBType {
121121

122122
uint64_t GetByteSize();
123123

124+
/// \return
125+
/// Whether the type is a pointer or a reference.
126+
bool IsPointerOrReferenceType();
127+
124128
bool IsPointerType();
125129

126130
bool IsReferenceType();

lldb/source/API/SBType.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ uint64_t SBType::GetByteSize() {
127127
return 0;
128128
}
129129

130+
bool SBType::IsPointerOrReferenceType() {
131+
return IsPointerType() || IsReferenceType();
132+
}
133+
130134
bool SBType::IsPointerType() {
131135
LLDB_INSTRUMENT_VA(this);
132136

lldb/test/API/tools/lldb-vscode/evaluate/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ int main(int argc, char const *argv[]) {
4343
my_bool_vec.push_back(true);
4444
my_bool_vec.push_back(false); // breakpoint 6
4545
my_bool_vec.push_back(true); // breakpoint 7
46-
46+
4747
return 0;
4848
}

lldb/test/API/tools/lldb-vscode/variables/TestVSCode_variables.py

Lines changed: 93 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ def verify_values(self, verify_dict, actual, varref_dict=None, expression=None):
4242
('"%s" value "%s" doesn\'t start with' ' "%s")')
4343
% (key, actual_value, verify_value),
4444
)
45+
if "notstartswith" in verify_dict:
46+
verify = verify_dict["notstartswith"]
47+
for key in verify:
48+
verify_value = verify[key]
49+
actual_value = actual[key]
50+
startswith = actual_value.startswith(verify_value)
51+
self.assertFalse(
52+
startswith,
53+
('"%s" value "%s" starts with' ' "%s")')
54+
% (key, actual_value, verify_value),
55+
)
4556
if "contains" in verify_dict:
4657
verify = verify_dict["contains"]
4758
for key in verify:
@@ -155,6 +166,7 @@ def do_test_scopes_variables_setVariable_evaluate(
155166
"argv": {
156167
"equals": {"type": "const char **"},
157168
"startswith": {"value": "0x"},
169+
"notstartswith": {"value": "0x0"},
158170
"hasVariablesReference": True,
159171
},
160172
"pt": {
@@ -166,8 +178,53 @@ def do_test_scopes_variables_setVariable_evaluate(
166178
"buffer": {"children": buffer_children},
167179
},
168180
},
181+
"pt_ptr": {
182+
"equals": {"type": "PointType *"},
183+
"startswith": {"value": "0x"},
184+
"notstartswith": {"value": "0x0"},
185+
"hasVariablesReference": True,
186+
},
187+
"another_pt_ptr": {
188+
"equals": {"type": "PointType *"},
189+
"startswith": {"value": "<null>"},
190+
"hasVariablesReference": True,
191+
},
169192
"x": {"equals": {"type": "int"}},
193+
"some_int": {
194+
"equals": {
195+
"type": "int",
196+
"value": "10",
197+
},
198+
},
199+
"some_int_ptr": {
200+
"equals": {"type": "int *"},
201+
"startswith": {"value": "0x"},
202+
"notstartswith": {"value": "0x0"},
203+
},
204+
"another_int_ptr": {
205+
"equals": {
206+
"type": "int *",
207+
"value": "<null>",
208+
},
209+
},
170210
}
211+
if enableAutoVariableSummaries:
212+
verify_locals["pt_ptr"] = {
213+
"equals": {"type": "PointType *"},
214+
"hasVariablesReference": True,
215+
"children": {
216+
"x": {"equals": {"type": "int", "value": "11"}},
217+
"y": {"equals": {"type": "int", "value": "22"}},
218+
"buffer": {"children": buffer_children},
219+
},
220+
}
221+
verify_locals["some_int_ptr"] = {
222+
"equals": {
223+
"type": "int *",
224+
"value": "20",
225+
},
226+
}
227+
171228
verify_globals = {
172229
"s_local": {"equals": {"type": "float", "value": "2.25"}},
173230
"::g_global": {"equals": {"type": "int", "value": "123"}},
@@ -297,9 +354,9 @@ def do_test_scopes_variables_setVariable_evaluate(
297354

298355
verify_locals["argc"]["equals"]["value"] = "123"
299356
verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
300-
verify_locals["x @ main.cpp:17"] = {"equals": {"type": "int", "value": "89"}}
301-
verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": "42"}}
302-
verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": "72"}}
357+
verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": "89"}}
358+
verify_locals["x @ main.cpp:25"] = {"equals": {"type": "int", "value": "42"}}
359+
verify_locals["x @ main.cpp:27"] = {"equals": {"type": "int", "value": "72"}}
303360

304361
self.verify_variables(verify_locals, self.vscode.get_local_variables())
305362

@@ -310,29 +367,29 @@ def do_test_scopes_variables_setVariable_evaluate(
310367
)
311368

312369
self.assertTrue(
313-
self.vscode.request_setVariable(1, "x @ main.cpp:17", 17)["success"]
370+
self.vscode.request_setVariable(1, "x @ main.cpp:23", 17)["success"]
314371
)
315372
self.assertTrue(
316-
self.vscode.request_setVariable(1, "x @ main.cpp:19", 19)["success"]
373+
self.vscode.request_setVariable(1, "x @ main.cpp:25", 19)["success"]
317374
)
318375
self.assertTrue(
319-
self.vscode.request_setVariable(1, "x @ main.cpp:21", 21)["success"]
376+
self.vscode.request_setVariable(1, "x @ main.cpp:27", 21)["success"]
320377
)
321378

322379
# The following should have no effect
323380
self.assertFalse(
324-
self.vscode.request_setVariable(1, "x @ main.cpp:21", "invalid")["success"]
381+
self.vscode.request_setVariable(1, "x @ main.cpp:27", "invalid")["success"]
325382
)
326383

327-
verify_locals["x @ main.cpp:17"]["equals"]["value"] = "17"
328-
verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
329-
verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
384+
verify_locals["x @ main.cpp:23"]["equals"]["value"] = "17"
385+
verify_locals["x @ main.cpp:25"]["equals"]["value"] = "19"
386+
verify_locals["x @ main.cpp:27"]["equals"]["value"] = "21"
330387

331388
self.verify_variables(verify_locals, self.vscode.get_local_variables())
332389

333390
# The plain x variable shold refer to the innermost x
334391
self.assertTrue(self.vscode.request_setVariable(1, "x", 22)["success"])
335-
verify_locals["x @ main.cpp:21"]["equals"]["value"] = "22"
392+
verify_locals["x @ main.cpp:27"]["equals"]["value"] = "22"
336393

337394
self.verify_variables(verify_locals, self.vscode.get_local_variables())
338395

@@ -349,9 +406,9 @@ def do_test_scopes_variables_setVariable_evaluate(
349406
names = [var["name"] for var in locals]
350407
# The first shadowed x shouldn't have a suffix anymore
351408
verify_locals["x"] = {"equals": {"type": "int", "value": "17"}}
352-
self.assertNotIn("x @ main.cpp:17", names)
353-
self.assertNotIn("x @ main.cpp:19", names)
354-
self.assertNotIn("x @ main.cpp:21", names)
409+
self.assertNotIn("x @ main.cpp:23", names)
410+
self.assertNotIn("x @ main.cpp:25", names)
411+
self.assertNotIn("x @ main.cpp:27", names)
355412

356413
self.verify_variables(verify_locals, locals)
357414

@@ -421,10 +478,32 @@ def do_test_scopes_and_evaluate_expansion(self, enableAutoVariableSummaries: boo
421478
},
422479
},
423480
},
481+
"pt_ptr": {
482+
"equals": {"type": "PointType *"},
483+
"hasVariablesReference": True,
484+
"missing": ["indexedVariables"],
485+
},
486+
"another_pt_ptr": {
487+
"equals": {"type": "PointType *"},
488+
"hasVariablesReference": True,
489+
"missing": ["indexedVariables"],
490+
},
424491
"x": {
425492
"equals": {"type": "int"},
426493
"missing": ["indexedVariables"],
427494
},
495+
"some_int": {
496+
"equals": {"type": "int"},
497+
"missing": ["indexedVariables"],
498+
},
499+
"some_int_ptr": {
500+
"equals": {"type": "int *"},
501+
"missing": ["indexedVariables"],
502+
},
503+
"another_int_ptr": {
504+
"equals": {"type": "int *"},
505+
"missing": ["indexedVariables"],
506+
},
428507
}
429508
self.verify_variables(verify_locals, locals)
430509

lldb/test/API/tools/lldb-vscode/variables/main.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ int test_indexedVariables();
1212
int main(int argc, char const *argv[]) {
1313
static float s_local = 2.25;
1414
PointType pt = { 11,22, {0}};
15+
PointType *pt_ptr = new PointType{11, 22, {0}};
16+
PointType *another_pt_ptr = nullptr;
1517
for (int i=0; i<BUFFER_SIZE; ++i)
1618
pt.buffer[i] = i;
19+
20+
int some_int = 10;
21+
int *some_int_ptr = new int{20};
22+
int *another_int_ptr = nullptr;
1723
int x = s_global - g_global - pt.y; // breakpoint 1
1824
{
1925
int x = 42;

lldb/tools/lldb-vscode/JSONUtils.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ static bool ShouldBeDereferencedForSummary(lldb::SBValue &v) {
200200
if (!g_vsc.enable_auto_variable_summaries)
201201
return false;
202202

203-
if (!v.GetType().IsPointerType() && !v.GetType().IsReferenceType())
203+
if (!v.GetType().IsPointerOrReferenceType())
204204
return false;
205205

206206
// If we are referencing a pointer, we don't dereference to avoid confusing
@@ -228,7 +228,24 @@ void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
228228
strm << "<error: " << error.GetCString() << ">";
229229
} else {
230230
auto tryDumpSummaryAndValue = [&strm](lldb::SBValue value) {
231-
llvm::StringRef val = value.GetValue();
231+
std::string val;
232+
// Whenever the value is a non-synthetic address, we format it ourselves
233+
// to use as few chars as possible because the variables pane on VS Code
234+
// is by default narrow.
235+
if (!value.IsSynthetic() && value.GetType().IsPointerOrReferenceType()) {
236+
lldb::addr_t address = value.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
237+
if (address == LLDB_INVALID_ADDRESS) {
238+
val = "<invalid address>";
239+
} else if (address == 0) {
240+
val = "<null>";
241+
} else {
242+
llvm::raw_string_ostream os(val);
243+
os << llvm::format_hex(address, 0);
244+
}
245+
} else {
246+
val = llvm::StringRef(value.GetValue()).str();
247+
}
248+
232249
llvm::StringRef summary = value.GetSummary();
233250
if (!val.empty()) {
234251
strm << val;

0 commit comments

Comments
 (0)