Skip to content

Commit 625d617

Browse files
committed
Fix Pavel's patch for ValueObjectVariables with complex DWARF expressions
to work with Swift's complex Synthetic variable structures. Pavel's patch is appropriate for children of ValueObjectVariables but not for synthetic children. This patch ensures that we only do the computation where appropriate. The patch is being discussed w.r.t. the llvm.org sources as: https://reviews.llvm.org/D83450 This change is to get it onto the 5.3 branch w/o having to wait for the resolution of that discussion. <rdar://problem/64209516>
1 parent d6ebd84 commit 625d617

File tree

8 files changed

+236
-0
lines changed

8 files changed

+236
-0
lines changed

lldb/include/lldb/Core/ValueObject.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,13 @@ class ValueObject : public UserID {
971971

972972
void SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType);
973973

974+
void UpdateChildrenAddressType() {
975+
GetRoot()->DoUpdateChildrenAddressType(*this);
976+
}
977+
978+
protected:
979+
virtual void DoUpdateChildrenAddressType(ValueObject &valobj) { return; };
980+
974981
private:
975982
virtual CompilerType MaybeCalculateCompleteType();
976983

lldb/include/lldb/Core/ValueObjectVariable.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ class ValueObjectVariable : public ValueObject {
6767

6868
protected:
6969
bool UpdateValue() override;
70+
71+
void DoUpdateChildrenAddressType(ValueObject &valobj) override;
7072

7173
CompilerType GetCompilerTypeImpl() override;
7274

lldb/source/Core/ValueObjectVariable.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,64 @@ bool ValueObjectVariable::UpdateValue() {
331331
m_resolved_value.SetContext(Value::eContextTypeInvalid, nullptr);
332332
}
333333
}
334+
334335
return m_error.Success();
335336
}
336337

338+
void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) {
339+
Value::ValueType value_type = valobj.GetValue().GetValueType();
340+
ExecutionContext exe_ctx(GetExecutionContextRef());
341+
Process *process = exe_ctx.GetProcessPtr();
342+
const bool process_is_alive = process && process->IsAlive();
343+
const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
344+
const bool is_pointer_or_ref =
345+
(type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0;
346+
347+
switch (value_type) {
348+
case Value::eValueTypeFileAddress:
349+
// If this type is a pointer, then its children will be considered load
350+
// addresses if the pointer or reference is dereferenced, but only if
351+
// the process is alive.
352+
//
353+
// There could be global variables like in the following code:
354+
// struct LinkedListNode { Foo* foo; LinkedListNode* next; };
355+
// Foo g_foo1;
356+
// Foo g_foo2;
357+
// LinkedListNode g_second_node = { &g_foo2, NULL };
358+
// LinkedListNode g_first_node = { &g_foo1, &g_second_node };
359+
//
360+
// When we aren't running, we should be able to look at these variables
361+
// using the "target variable" command. Children of the "g_first_node"
362+
// always will be of the same address type as the parent. But children
363+
// of the "next" member of LinkedListNode will become load addresses if
364+
// we have a live process, or remain a file address if it was a file
365+
// address.
366+
if (process_is_alive && is_pointer_or_ref)
367+
valobj.SetAddressTypeOfChildren(eAddressTypeLoad);
368+
else
369+
valobj.SetAddressTypeOfChildren(eAddressTypeFile);
370+
break;
371+
case Value::eValueTypeHostAddress:
372+
// Same as above for load addresses, except children of pointer or refs
373+
// are always load addresses. Host addresses are used to store freeze
374+
// dried variables. If this type is a struct, the entire struct
375+
// contents will be copied into the heap of the
376+
// LLDB process, but we do not currently follow any pointers.
377+
if (is_pointer_or_ref)
378+
valobj.SetAddressTypeOfChildren(eAddressTypeLoad);
379+
else
380+
valobj.SetAddressTypeOfChildren(eAddressTypeHost);
381+
break;
382+
case Value::eValueTypeLoadAddress:
383+
case Value::eValueTypeScalar:
384+
case Value::eValueTypeVector:
385+
valobj.SetAddressTypeOfChildren(eAddressTypeLoad);
386+
break;
387+
}
388+
}
389+
390+
391+
337392
bool ValueObjectVariable::IsInScope() {
338393
const ExecutionContextRef &exe_ctx_ref = GetExecutionContextRef();
339394
if (exe_ctx_ref.HasFrameRef()) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
all: libmod.dylib a.out
4+
5+
include Makefile.rules
6+
LD_EXTRAS = -lmod -L$(BUILDDIR)
7+
SWIFTFLAGS_EXTRAS = -I$(BUILDDIR)
8+
9+
libmod.dylib: mod.swift
10+
$(MAKE) MAKE_DSYM=YES CC=$(CC) SWIFTC=$(SWIFTC) \
11+
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \
12+
BASENAME=mod \
13+
SWIFTFLAGS_EXTRAS="-I$(BUILDDIR) -enable-library-evolution" \
14+
VPATH=$(SRCDIR) -I $(SRCDIR) -f $(SRCDIR)/dylib.mk all
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# TestResilientObjectInOptional.py
2+
#
3+
# This source file is part of the Swift.org open source project
4+
#
5+
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
# Licensed under Apache License v2.0 with Runtime Library Exception
7+
#
8+
# See https://swift.org/LICENSE.txt for license information
9+
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
#
11+
# ------------------------------------------------------------------------------
12+
"""
13+
Test that we can extract a resilient object from an Optional
14+
"""
15+
import lldb
16+
from lldbsuite.test.lldbtest import *
17+
from lldbsuite.test.decorators import *
18+
import lldbsuite.test.lldbutil as lldbutil
19+
import unittest2
20+
21+
class TestResilientObjectInOptional(TestBase):
22+
23+
mydir = TestBase.compute_mydir(__file__)
24+
25+
@skipUnlessDarwin
26+
@swiftTest
27+
def test_optional_of_resilient(self):
28+
"""Test that can extract resilient objects from an Optional"""
29+
self.build()
30+
self.doTest()
31+
32+
def setUp(self):
33+
TestBase.setUp(self)
34+
35+
def doTest(self):
36+
exe_name = "a.out"
37+
exe_path = self.getBuildArtifact(exe_name)
38+
39+
source_name = "main.swift"
40+
source_spec = lldb.SBFileSpec(source_name)
41+
print("Looking for executable at: %s"%(exe_name))
42+
target = self.dbg.CreateTarget(exe_path)
43+
self.assertTrue(target, VALID_TARGET)
44+
self.registerSharedLibrariesWithTarget(target, ['mod'])
45+
46+
target, process, thread, breakpoint = lldbutil.run_to_source_breakpoint(
47+
self, "break here", source_spec, exe_name=exe_path)
48+
49+
frame = thread.frames[0]
50+
51+
# First try getting a non-resilient optional, to make sure that
52+
# part isn't broken:
53+
t_opt_var = frame.FindVariable("t_opt")
54+
self.assertTrue(t_opt_var.GetError().Success(), "Made t_opt value object")
55+
t_a_var = t_opt_var.GetChildMemberWithName("a")
56+
self.assertTrue(t_a_var.GetError().Success(), "The child was a")
57+
lldbutil.check_variable(self, t_a_var, False, value="2")
58+
59+
# Make sure we can print an optional of a resilient type...
60+
# If we got the value out of the optional correctly, then
61+
# it's child will be "a".
62+
# First do this with "frame var":
63+
opt_var = frame.FindVariable("s_opt")
64+
self.assertTrue(opt_var.GetError().Success(), "Made s_opt value object")
65+
a_var = opt_var.GetChildMemberWithName("a")
66+
self.assertTrue(a_var.GetError().Success(), "The resilient child was 'a'")
67+
lldbutil.check_variable(self, a_var, False, value="1")
68+
69+
if __name__ == '__main__':
70+
import atexit
71+
lldb.SBDebugger.Initialize()
72+
atexit.register(lldb.SBDebugger.Terminate)
73+
unittest2.main()
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DYLIB_ONLY := YES
2+
DYLIB_NAME := $(BASENAME)
3+
DYLIB_SWIFT_SOURCES := $(DYLIB_NAME).swift
4+
include Makefile.rules
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// main.swift
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// -----------------------------------------------------------------------------
12+
import mod
13+
14+
// This is the same as mod.S to make it easier to
15+
// compare the reconstruction of the resilient and non-resilient types.
16+
struct T {
17+
public var a = 2
18+
fileprivate var s1 = "I"
19+
fileprivate var s2 = "AM"
20+
fileprivate var s3 = "LARGE"
21+
fileprivate var s4 = "!!"
22+
23+
public init() {}
24+
}
25+
26+
func main() {
27+
initGlobal()
28+
let s = S()
29+
let s_opt : Optional<S> = s
30+
let t = T()
31+
let t_opt : Optional<T> = t
32+
print(s.a) // break here
33+
}
34+
35+
main()
36+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// mod.a.swift
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// -----------------------------------------------------------------------------
12+
13+
public struct S {
14+
public var a = 1
15+
fileprivate var s1 = "i"
16+
fileprivate var s2 = "am"
17+
fileprivate var s3 = "large"
18+
fileprivate var s4 = "!"
19+
20+
public init() {}
21+
}
22+
23+
fileprivate class Message { fileprivate var s = "hello" }
24+
fileprivate struct NotBitwiseTakable {
25+
fileprivate weak var msg : Message?
26+
}
27+
28+
fileprivate struct FixedContainer {
29+
var s = S()
30+
}
31+
32+
fileprivate var g_msg = Message()
33+
fileprivate var g_b = NotBitwiseTakable()
34+
fileprivate var g_s = S()
35+
fileprivate var g_t = (S(), S())
36+
fileprivate var g_c = FixedContainer()
37+
38+
public func initGlobal() -> Int {
39+
g_b.msg = g_msg
40+
return g_s.a + g_t.0.a + g_c.s.a
41+
}
42+
43+
public func fA(_ x: S) -> Int {
44+
return x.a
45+
}

0 commit comments

Comments
 (0)