Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lldb/source/ValueObject/DILEval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ Interpreter::Visit(const UnaryOpNode *node) {
rhs = dynamic_rhs;

lldb::ValueObjectSP child_sp = rhs->Dereference(error);
if (!child_sp && m_use_synthetic) {
if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) {
error.Clear();
child_sp = synth_obj_sp->Dereference(error);
}
}
if (error.Fail())
return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
node->GetLocation());
Expand Down Expand Up @@ -280,6 +286,7 @@ Interpreter::Visit(const MemberOfNode *node) {
auto base_or_err = Evaluate(node->GetBase());
if (!base_or_err)
return base_or_err;
bool expr_is_ptr = node->GetIsArrow();
lldb::ValueObjectSP base = *base_or_err;

// Perform some basic type & correctness checking.
Expand Down Expand Up @@ -319,11 +326,11 @@ Interpreter::Visit(const MemberOfNode *node) {
return llvm::make_error<DILDiagnosticError>(
m_expr, errMsg, node->GetLocation(), node->GetFieldName().size());
}
expr_is_ptr = false;
}
}

if (m_check_ptr_vs_member) {
bool expr_is_ptr = node->GetIsArrow();
bool base_is_ptr = base->IsPointerType();

if (expr_is_ptr != base_is_ptr) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
Make sure 'frame var' using DIL parser/evaluator works for bit fields.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil

import os
import shutil
import time

class TestFrameVarDILBitField(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True

def test_frame_var(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here",
lldb.SBFileSpec("main.cpp"))

self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("bf.a", value="1023")
self.expect_var_path("bf.b", value="9")
self.expect_var_path("bf.c", value="false")
self.expect_var_path("bf.d", value="true")

self.expect_var_path("abf.a", value="1023")
self.expect_var_path("abf.b", value="'\\x0f'")
self.expect_var_path("abf.c", value="3")

# Perform an operation to ensure we actually read the value.
# Address-of is not allowed for bit-fields.
self.expect("frame variable '&bf.a'", error=True,
substrs=["'bf.a' doesn't have a valid address"])
44 changes: 44 additions & 0 deletions lldb/test/API/commands/frame/var-dil/basics/BitField/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <cstdint>

int
main(int argc, char **argv)
{
enum BitFieldEnum : uint32_t { kZero, kOne };

struct BitFieldStruct {
uint16_t a : 10;
uint32_t b : 4;
bool c : 1;
bool d : 1;
int32_t e : 32;
uint32_t f : 32;
uint32_t g : 31;
uint64_t h : 31;
uint64_t i : 33;
BitFieldEnum j : 10;
};

BitFieldStruct bf;
bf.a = 0b1111111111;
bf.b = 0b1001;
bf.c = 0b0;
bf.d = 0b1;
bf.e = 0b1;
bf.f = 0b1;
bf.g = 0b1;
bf.h = 0b1;
bf.i = 0b1;
bf.j = BitFieldEnum::kOne;

struct AlignedBitFieldStruct {
uint16_t a : 10;
uint8_t b : 4;
unsigned char : 0;
uint16_t c : 2;
};

uint32_t data = ~0;
AlignedBitFieldStruct abf = (AlignedBitFieldStruct&)data;

return 0; // Set a breakpoint here
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Make sure 'frame var' using DIL parser/evaluator works for indirection.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil

import os
import shutil
import time

class TestFrameVarDILIndirection(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True

def test_frame_var(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here",
lldb.SBFileSpec("main.cpp"))

self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("*p", value="1")
self.expect_var_path("p", type="int *")
self.expect_var_path("*my_p", value="1")
self.expect_var_path("my_p", type="myp")
self.expect_var_path("*my_pr", type="int *")
self.expect_var_path("my_pr", type="mypr")

self.expect("frame variable '*1'", error=True,
substrs=["Unexpected token: <'1' (numeric_constant)>"])
self.expect("frame variable '*val'", error=True,
substrs=["dereference failed: not a pointer, reference or array type: (int) val"])
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
int
main(int argc, char **argv)
{
int val = 1;
int* p = &val;

typedef int* myp;
myp my_p = &val;

typedef int*& mypr;
mypr my_pr = p;

return 0; // Set a breakpoint here
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Test DIL pointer dereferencing.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil

import os
import shutil
import time

class TestFrameVarDILPointerDereference(TestBase):
NO_DEBUG_INFO_TESTCASE = True

def test_frame_var(self):
self.build()
lldbutil.run_to_source_breakpoint(
self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
)

self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("*p_int0", value="0")
self.expect_var_path("*cp_int5", value="5")
self.expect_var_path("&pp_void0[2]", type="void **")
self.expect_var_path("**pp_int0", value="0")
self.expect_var_path("&**pp_int0", type="int *")
Comment on lines +25 to +29
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the goal here is to explicitly check handling pointer arithmetic, you may want to add additional checks for the values you get this way. expect_var_path returns the SBValue it has located, so you could do something like:

pp_void0_2_got = self.expect_var_path("&pp_void0[2]", type="void **")
pp_void0_2_exp = self.expect_var_path("pp_void0_2", type="void **") # Initialized in C++ code to point to the same value
self.assertEqual(pp_void0_2_got.GetValueAsAddress(), pp_void0_2_exp.GetValueAsAddress())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion! Done.

self.expect("frame variable '&p_void[0]'", error=True,
substrs=["subscript of pointer to incomplete type 'void'"])
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <cstddef>

int main (int argc, char **argv) {
int* p_null = nullptr;
const char* p_char1 = "hello";

typedef const char* my_char_ptr;
my_char_ptr my_p_char1 = p_char1;

int offset = 5;
int array[10];
array[0] = 0;
array[offset] = offset;

int(&array_ref)[10] = array;

int* p_int0 = &array[0];
int** pp_int0 = &p_int0;
const int* cp_int0 = &array[0];
const int* cp_int5 = &array[offset];

typedef int* td_int_ptr_t;
td_int_ptr_t td_int_ptr0 = &array[0];

void* p_void = (void*)p_char1;
void** pp_void0 = &p_void;
void** pp_void1 = pp_void0 + 1;

std::nullptr_t std_nullptr_t = nullptr;

return 0; // Set a breakpoint here
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
Make sure 'frame var' using DIL parser/evaluator works for namespaces.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil

import os
import shutil
import time

class TestFrameVarDILQualifiedId(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True

def test_frame_var(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here",
lldb.SBFileSpec("main.cpp"))

self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("::ns::i", value="1")
self.expect_var_path("ns::i", value="1")
self.expect_var_path("::ns::ns::i", value="2")
self.expect_var_path("ns::ns::i", value="2")
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace ns {

int i = 1;

namespace ns {

int i = 2;

} // namespace ns

} // namespace ns

int
main(int argc, char **argv)
{

return 0; // Set a breakpoint here
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CXX_SOURCES := main.cpp
CXXFLAGS_EXTRAS := -std=c++14

USE_LIBCPP := 1

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""
Make sure 'frame var' using DIL parser/evaluator works for shared/weak pointers.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil

import os
import shutil
import time

class TestFrameVarDILSharedPtr(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True

def test_frame_var(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here",
lldb.SBFileSpec("main.cpp"))

self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("ptr_node.__ptr_",
type="std::shared_ptr<NodeS>::element_type *")
self.expect_var_path("ptr_node.__ptr_->value", value="1")
self.expect_var_path("ptr_node.__ptr_->next.__ptr_->value", value="2")

self.expect_var_path("ptr_int.__ptr_",
type="std::shared_ptr<int>::element_type *")
self.expect_var_path("*ptr_int.__ptr_", value="1")
self.expect_var_path("ptr_int_weak.__ptr_",
type="std::weak_ptr<int>::element_type *")
self.expect_var_path("*ptr_int_weak.__ptr_", value="1")
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
Make sure 'frame var' using DIL parser/evaluator works for shared pointer deref.
"""

import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test import lldbutil

import os
import shutil
import time

class TestFrameVarDILSharedPtrDeref(TestBase):
# If your test case doesn't stress debug info, then
# set this to true. That way it won't be run once for
# each debug info format.
NO_DEBUG_INFO_TESTCASE = True

def test_frame_var(self):
self.build()
lldbutil.run_to_source_breakpoint(self, "Set a breakpoint here",
lldb.SBFileSpec("main.cpp"))

self.runCmd("settings set target.experimental.use-DIL true")
self.expect_var_path("ptr_node->value", value="1")
self.expect_var_path("ptr_node->next->value", value="2")
self.expect_var_path("(*ptr_node).value", value="1")
self.expect_var_path("(*(*ptr_node).next).value", value="2")
26 changes: 26 additions & 0 deletions lldb/test/API/commands/frame/var-dil/basics/SharedPtr/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <memory>

int
main(int argc, char **argv)
{

struct NodeS {
std::shared_ptr<NodeS> next;
int value;
};
auto ptr_node = std::shared_ptr<NodeS>(new NodeS{nullptr, 2});
ptr_node = std::shared_ptr<NodeS>(new NodeS{std::move(ptr_node), 1});

std::shared_ptr<char> ptr_null;
auto ptr_int = std::make_shared<int>(1);
auto ptr_float = std::make_shared<float>(1.1f);

std::weak_ptr<int> ptr_int_weak = ptr_int;

std::shared_ptr<void> ptr_void = ptr_int;

// TestSharedPtr
// TestSharedPtrDeref
// TestSharedPtrCompare
return 0; // Set a breakpoint here
}
Loading
Loading