Skip to content

Commit 6d3ad9d

Browse files
authored
[LLDB] Update DIL handling of array subscripting. (#151605)
This updates the DIL code for handling array subscripting to more closely match and handle all the cases from the original 'frame var' implementation. Also updates the DIL array subscripting test. This particularly fixes some issues with handling synthetic children, objc pointers, and accessing specific bits within scalar data types.
1 parent 11c2240 commit 6d3ad9d

File tree

4 files changed

+126
-34
lines changed

4 files changed

+126
-34
lines changed

lldb/source/ValueObject/DILEval.cpp

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -330,40 +330,83 @@ Interpreter::Visit(const ArraySubscriptNode *node) {
330330
return lhs_or_err;
331331
lldb::ValueObjectSP base = *lhs_or_err;
332332

333-
// Check to see if 'base' has a synthetic value; if so, try using that.
333+
StreamString var_expr_path_strm;
334334
uint64_t child_idx = node->GetIndex();
335-
if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) {
336-
llvm::Expected<uint32_t> num_children =
337-
synthetic->GetNumChildren(child_idx + 1);
338-
if (!num_children)
339-
return llvm::make_error<DILDiagnosticError>(
340-
m_expr, toString(num_children.takeError()), node->GetLocation());
341-
if (child_idx >= *num_children) {
342-
std::string message = llvm::formatv(
335+
lldb::ValueObjectSP child_valobj_sp;
336+
bool is_incomplete_array = false;
337+
CompilerType base_type = base->GetCompilerType().GetNonReferenceType();
338+
base->GetExpressionPath(var_expr_path_strm);
339+
if (base_type.IsPointerType()) {
340+
child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
341+
if (!child_valobj_sp) {
342+
std::string err_msg = llvm::formatv(
343+
"failed to use pointer as array for index {0} for "
344+
"\"({1}) {2}\"",
345+
child_idx, base->GetTypeName().AsCString("<invalid type>"),
346+
var_expr_path_strm.GetData());
347+
if (base_type.IsPointerToVoid())
348+
err_msg = "subscript of pointer to incomplete type 'void'";
349+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
350+
node->GetLocation());
351+
}
352+
} else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) {
353+
child_valobj_sp = base->GetChildAtIndex(child_idx);
354+
if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic))
355+
child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
356+
if (!child_valobj_sp) {
357+
std::string err_msg = llvm::formatv(
343358
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
344359
base->GetTypeName().AsCString("<invalid type>"),
345-
base->GetName().AsCString());
346-
return llvm::make_error<DILDiagnosticError>(m_expr, message,
360+
var_expr_path_strm.GetData());
361+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
347362
node->GetLocation());
348363
}
349-
if (lldb::ValueObjectSP child_valobj_sp =
350-
synthetic->GetChildAtIndex(child_idx))
351-
return child_valobj_sp;
364+
} else if (base_type.IsScalarType()) {
365+
child_valobj_sp =
366+
base->GetSyntheticBitFieldChild(child_idx, child_idx, true);
367+
if (!child_valobj_sp) {
368+
std::string err_msg = llvm::formatv(
369+
"bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx,
370+
child_idx, base->GetTypeName().AsCString("<invalid type>"),
371+
var_expr_path_strm.GetData());
372+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
373+
node->GetLocation(), 1);
374+
}
375+
} else {
376+
lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
377+
if (!m_use_synthetic || !synthetic || synthetic == base) {
378+
std::string err_msg =
379+
llvm::formatv("\"{0}\" is not an array type",
380+
base->GetTypeName().AsCString("<invalid type>"));
381+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
382+
node->GetLocation(), 1);
383+
}
384+
if (static_cast<uint32_t>(child_idx) >=
385+
synthetic->GetNumChildrenIgnoringErrors(child_idx + 1)) {
386+
std::string err_msg = llvm::formatv(
387+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
388+
base->GetTypeName().AsCString("<invalid type>"),
389+
var_expr_path_strm.GetData());
390+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
391+
node->GetLocation(), 1);
392+
}
393+
child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
394+
if (!child_valobj_sp) {
395+
std::string err_msg = llvm::formatv(
396+
"array index {0} is not valid for \"({1}) {2}\"", child_idx,
397+
base->GetTypeName().AsCString("<invalid type>"),
398+
var_expr_path_strm.GetData());
399+
return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
400+
node->GetLocation(), 1);
401+
}
352402
}
353403

354-
auto base_type = base->GetCompilerType().GetNonReferenceType();
355-
if (!base_type.IsPointerType() && !base_type.IsArrayType())
356-
return llvm::make_error<DILDiagnosticError>(
357-
m_expr, "subscripted value is not an array or pointer",
358-
node->GetLocation());
359-
if (base_type.IsPointerToVoid())
360-
return llvm::make_error<DILDiagnosticError>(
361-
m_expr, "subscript of pointer to incomplete type 'void'",
362-
node->GetLocation());
363-
364-
if (base_type.IsArrayType()) {
365-
if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx))
366-
return child_valobj_sp;
404+
if (child_valobj_sp) {
405+
if (m_use_dynamic != lldb::eNoDynamicValues) {
406+
if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
407+
child_valobj_sp = std::move(dynamic_sp);
408+
}
409+
return child_valobj_sp;
367410
}
368411

369412
int64_t signed_child_idx = node->GetIndex();

lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/TestFrameVarDILArraySubscript.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,18 @@ def test_subscript(self):
6969
substrs=["expected 'r_square', got: <'.'"],
7070
)
7171

72-
# Base should be a "pointer to T" and index should be of an integral type.
73-
self.expect(
74-
"frame var 'idx_1[0]'",
75-
error=True,
76-
substrs=["subscripted value is not an array or pointer"],
77-
)
72+
# Test accessing bits in scalar types.
73+
self.expect_var_path("idx_1[0]", value="1")
74+
self.expect_var_path("idx_1[1]", value="0")
75+
76+
# Bit adcess not valid for a reference.
7877
self.expect(
7978
"frame var 'idx_1_ref[0]'",
8079
error=True,
81-
substrs=["subscripted value is not an array or pointer"],
80+
substrs=["bitfield range 0-0 is not valid"],
8281
)
82+
83+
# Base should be a "pointer to T" and index should be of an integral type.
8384
self.expect(
8485
"frame var 'int_arr[int_ptr]'",
8586
error=True,
@@ -105,6 +106,8 @@ def test_subscript_synthetic(self):
105106
)
106107

107108
self.runCmd("settings set target.experimental.use-DIL true")
109+
self.runCmd("script from myArraySynthProvider import *")
110+
self.runCmd("type synth add -l myArraySynthProvider myArray")
108111

109112
# Test synthetic value subscription
110113
self.expect_var_path("vector[1]", value="2")
@@ -113,3 +116,7 @@ def test_subscript_synthetic(self):
113116
error=True,
114117
substrs=["array index 100 is not valid"],
115118
)
119+
self.expect(
120+
"frame var 'ma_ptr[0]'",
121+
substrs=["(myArray) ma_ptr[0] = ([0] = 7, [1] = 8, [2] = 9, [3] = 10)"],
122+
)

lldb/test/API/commands/frame/var-dil/basics/ArraySubscript/main.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#include <vector>
22

3+
class myArray {
4+
public:
5+
int m_array[4] = {7, 8, 9, 10};
6+
int m_arr_size = 4;
7+
};
8+
39
int main(int argc, char **argv) {
410
int int_arr[] = {1, 2, 3};
511
int *int_ptr = int_arr;
@@ -29,5 +35,8 @@ int main(int argc, char **argv) {
2935

3036
std::vector<int> vector = {1, 2, 3};
3137

38+
myArray ma;
39+
myArray *ma_ptr = &ma;
40+
3241
return 0; // Set a breakpoint here
3342
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import lldb
2+
3+
4+
class myArraySynthProvider:
5+
def __init__(self, valobj, dict):
6+
self.valobj = valobj
7+
8+
def num_children(self):
9+
size_valobj = self.valobj.GetChildMemberWithName("m_arr_size")
10+
if size_valobj:
11+
return size_valobj.GetValueAsUnsigned(0)
12+
return 0
13+
14+
def get_child_at_index(self, index):
15+
size_valobj = self.valobj.GetChildMemberWithName("m_arr_size")
16+
arr = self.valobj.GetChildMemberWithName("m_array")
17+
if not size_valobj or not arr:
18+
return None
19+
max_idx = size_valobj.GetValueAsUnsigned(0)
20+
if index >= max_idx:
21+
return None
22+
return arr.GetChildAtIndex(index)
23+
24+
def get_child_index(self, name):
25+
if name == "[0]":
26+
return 0
27+
if name == "[1]":
28+
return
29+
if name == "[2]":
30+
return 2
31+
if name == "[3]":
32+
return 3
33+
return -1

0 commit comments

Comments
 (0)