Skip to content

Commit 14b54c5

Browse files
authored
Merge pull request #1276 from medismailben/swift/master
[lldb/formatter] Add Swift.UnsafeBufferPointer data formatter
2 parents 44cecca + df9551d commit 14b54c5

File tree

8 files changed

+441
-0
lines changed

8 files changed

+441
-0
lines changed

lldb/source/Plugins/Language/Swift/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_lldb_library(lldbPluginSwiftLanguage PLUGIN
1414
SwiftOptional.cpp
1515
SwiftRuntimeFailureRecognizer.cpp
1616
SwiftSet.cpp
17+
SwiftUnsafeTypes.cpp
1718

1819
LINK_LIBS
1920
lldbCore

lldb/source/Plugins/Language/Swift/SwiftFormatters.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "SwiftOptionSet.h"
3030
#include "SwiftOptional.h"
3131
#include "SwiftSet.h"
32+
#include "SwiftUnsafeTypes.h"
3233

3334
namespace lldb_private {
3435
namespace formatters {

lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,13 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
326326
"Swift.Array summary provider",
327327
ConstString("_TtCs22__SwiftDeferredNSArray"), summary_flags, false);
328328

329+
AddCXXSummary(
330+
swift_category_sp,
331+
lldb_private::formatters::swift::UnsafeBufferPointerSummaryProvider,
332+
"Swift.Unsafe(Mutable)BufferPointer",
333+
ConstString("^Swift.Unsafe(Mutable)?BufferPointer<.+>$"), summary_flags,
334+
true);
335+
329336
DictionaryConfig::Get()
330337
.RegisterSummaryProviders(swift_category_sp, summary_flags);
331338
SetConfig::Get()
@@ -383,6 +390,13 @@ static void LoadSwiftFormatters(lldb::TypeCategoryImplSP swift_category_sp) {
383390
synth_flags,
384391
false);
385392

393+
AddCXXSynthetic(swift_category_sp,
394+
lldb_private::formatters::swift::
395+
UnsafeBufferPointerSyntheticFrontEndCreator,
396+
"Swift.Unsafe(Mutable)BufferPointer",
397+
ConstString("^Swift.Unsafe(Mutable)?BufferPointer<.+>$"),
398+
synth_flags, true);
399+
386400
DictionaryConfig::Get()
387401
.RegisterSyntheticChildrenCreators(swift_category_sp, synth_flags);
388402
SetConfig::Get()
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#include "SwiftUnsafeTypes.h"
2+
3+
#include "lldb/DataFormatters/TypeSynthetic.h"
4+
#include "lldb/Symbol/SwiftASTContext.h"
5+
#include "lldb/Target/SwiftLanguageRuntime.h"
6+
7+
#include <utility>
8+
9+
using namespace lldb;
10+
using namespace lldb_private;
11+
12+
class SwiftUnsafeBufferPointer {
13+
public:
14+
SwiftUnsafeBufferPointer(ValueObject &valobj);
15+
size_t GetCount() const { return m_count; }
16+
addr_t GetStartAddress() const { return m_start_addr; }
17+
CompilerType GetElementType() const { return m_elem_type; }
18+
bool Update();
19+
20+
private:
21+
ValueObject &m_valobj;
22+
size_t m_count;
23+
addr_t m_start_addr;
24+
CompilerType m_elem_type;
25+
};
26+
27+
SwiftUnsafeBufferPointer::SwiftUnsafeBufferPointer(ValueObject &valobj)
28+
: m_valobj(*valobj.GetNonSyntheticValue().get()) {}
29+
30+
bool SwiftUnsafeBufferPointer::Update() {
31+
if (!m_valobj.GetNumChildren())
32+
return false;
33+
34+
// Here is the layout of Swift's Unsafe[Mutable]BufferPointer.
35+
//
36+
// ▿ UnsafeBufferPointer
37+
// ▿ _position : Optional<UnsafePointer<Int>>
38+
// ▿ some : UnsafePointer<Int>
39+
// - pointerValue : Int
40+
// - count : Int
41+
//
42+
// The structure has 2 children:
43+
// 1. The buffer `count` child stored as a Swift `Int` type. This entry is a
44+
// "value-providing synthetic children", so lldb need to access to its
45+
// children in order to get the actual value.
46+
// 2. An Optional UnsafePointer to the buffer start address. To access the
47+
// pointer address, lldb unfolds every value object child until reaching
48+
// `pointerValue`.
49+
50+
static ConstString g_count("count");
51+
ValueObjectSP count_value_sp(m_valobj.GetChildMemberWithName(g_count, true));
52+
if (!count_value_sp)
53+
return false;
54+
55+
ValueObjectSP value_provided_child_sp = nullptr;
56+
57+
// Implement Swift's 'value-providing synthetic children' workaround.
58+
// Depending on whether the value object type is a primitive or a structure,
59+
// lldb should prioritize the synthetic value children.
60+
// If it has no synthetic children then fallback to non synthetic children.
61+
ValueObjectSP synthetic = count_value_sp->GetSyntheticValue();
62+
if (synthetic)
63+
value_provided_child_sp = synthetic->GetChildAtIndex(0, true);
64+
if (!value_provided_child_sp)
65+
value_provided_child_sp = count_value_sp->GetChildAtIndex(0, true);
66+
// If neither child exists, fail.
67+
if (!value_provided_child_sp)
68+
return false;
69+
70+
size_t count = value_provided_child_sp->GetValueAsUnsigned(UINT64_MAX);
71+
72+
if (count == UINT64_MAX)
73+
return false;
74+
75+
m_count = count;
76+
77+
static ConstString g_position("_position");
78+
ValueObjectSP position_value_sp(
79+
m_valobj.GetChildMemberWithName(g_position, true));
80+
if (!position_value_sp || !position_value_sp->GetNumChildren())
81+
return false;
82+
83+
ValueObjectSP some_value_sp = position_value_sp->GetChildAtIndex(0, true);
84+
if (!some_value_sp || !some_value_sp->GetNumChildren())
85+
return false;
86+
87+
CompilerType argument_type;
88+
89+
if (CompilerType type = some_value_sp->GetCompilerType())
90+
argument_type = SwiftASTContext::GetGenericArgumentType(type, 0);
91+
92+
if (!argument_type.IsValid())
93+
return nullptr;
94+
95+
m_elem_type = argument_type;
96+
97+
ValueObjectSP pointer_value_sp = some_value_sp->GetChildAtIndex(0, true);
98+
if (!pointer_value_sp)
99+
return false;
100+
101+
addr_t addr = pointer_value_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
102+
103+
if (!addr || addr == LLDB_INVALID_ADDRESS)
104+
return false;
105+
106+
m_start_addr = addr;
107+
108+
return true;
109+
}
110+
111+
bool lldb_private::formatters::swift::UnsafeBufferPointerSummaryProvider(
112+
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
113+
114+
SwiftUnsafeBufferPointer swift_ubp(valobj);
115+
116+
if (!swift_ubp.Update())
117+
return false;
118+
119+
size_t count = swift_ubp.GetCount();
120+
addr_t addr = swift_ubp.GetStartAddress();
121+
122+
stream.Printf("%zu %s (0x%" PRIx64 ")", count,
123+
(count == 1) ? "value" : "values", addr);
124+
125+
return true;
126+
}
127+
128+
namespace lldb_private {
129+
namespace formatters {
130+
namespace swift {
131+
class UnsafeBufferPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
132+
public:
133+
UnsafeBufferPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
134+
135+
virtual size_t CalculateNumChildren();
136+
137+
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx);
138+
139+
virtual bool Update();
140+
141+
virtual bool MightHaveChildren();
142+
143+
virtual size_t GetIndexOfChildWithName(ConstString name);
144+
145+
virtual ~UnsafeBufferPointerSyntheticFrontEnd() = default;
146+
147+
private:
148+
ExecutionContextRef m_exe_ctx_ref;
149+
uint8_t m_ptr_size;
150+
lldb::ByteOrder m_order;
151+
152+
SwiftUnsafeBufferPointer m_unsafe_ptr;
153+
size_t m_element_stride;
154+
DataBufferSP m_buffer_sp;
155+
std::vector<ValueObjectSP> m_children;
156+
};
157+
} // namespace swift
158+
} // namespace formatters
159+
} // namespace lldb_private
160+
161+
lldb_private::formatters::swift::UnsafeBufferPointerSyntheticFrontEnd::
162+
UnsafeBufferPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
163+
: SyntheticChildrenFrontEnd(*valobj_sp.get()),
164+
m_unsafe_ptr(*valobj_sp.get()) {
165+
166+
ProcessSP process_sp = valobj_sp->GetProcessSP();
167+
if (!process_sp)
168+
return;
169+
170+
m_ptr_size = process_sp->GetAddressByteSize();
171+
m_order = process_sp->GetByteOrder();
172+
173+
if (valobj_sp)
174+
Update();
175+
}
176+
177+
size_t lldb_private::formatters::swift::UnsafeBufferPointerSyntheticFrontEnd::
178+
CalculateNumChildren() {
179+
return m_unsafe_ptr.GetCount();
180+
}
181+
182+
lldb::ValueObjectSP lldb_private::formatters::swift::
183+
UnsafeBufferPointerSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
184+
const size_t num_children = CalculateNumChildren();
185+
186+
if (idx >= num_children || idx >= m_children.size())
187+
return lldb::ValueObjectSP();
188+
189+
return m_children[idx];
190+
}
191+
192+
bool lldb_private::formatters::swift::UnsafeBufferPointerSyntheticFrontEnd::
193+
Update() {
194+
m_children.clear();
195+
ValueObjectSP valobj_sp = m_backend.GetSP();
196+
if (!valobj_sp)
197+
return false;
198+
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
199+
200+
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
201+
if (!process_sp)
202+
return false;
203+
if (!m_unsafe_ptr.Update())
204+
return false;
205+
206+
const addr_t start_addr = m_unsafe_ptr.GetStartAddress();
207+
const size_t num_children = CalculateNumChildren();
208+
const CompilerType element_type = m_unsafe_ptr.GetElementType();
209+
210+
auto stride = element_type.GetByteStride(process_sp.get());
211+
if (!stride)
212+
return false;
213+
214+
m_element_stride = *stride;
215+
216+
if (m_children.empty()) {
217+
size_t buffer_size = num_children * m_element_stride;
218+
m_buffer_sp.reset(new DataBufferHeap(buffer_size, 0));
219+
220+
Status error;
221+
size_t read_bytes = process_sp->ReadMemory(
222+
start_addr, m_buffer_sp->GetBytes(), buffer_size, error);
223+
224+
if (!read_bytes || error.Fail())
225+
return false;
226+
227+
DataExtractor buffer_data(m_buffer_sp->GetBytes(),
228+
m_buffer_sp->GetByteSize(), m_order, m_ptr_size);
229+
230+
for (size_t i = 0; i < num_children; i++) {
231+
StreamString idx_name;
232+
idx_name.Printf("[%" PRIu64 "]", i);
233+
DataExtractor data(buffer_data, i * m_element_stride, m_element_stride);
234+
m_children.push_back(CreateValueObjectFromData(
235+
idx_name.GetString(), data, m_exe_ctx_ref, element_type));
236+
}
237+
}
238+
239+
return m_children.size() == num_children;
240+
}
241+
242+
bool lldb_private::formatters::swift::UnsafeBufferPointerSyntheticFrontEnd::
243+
MightHaveChildren() {
244+
return m_unsafe_ptr.GetCount();
245+
}
246+
247+
size_t lldb_private::formatters::swift::UnsafeBufferPointerSyntheticFrontEnd::
248+
GetIndexOfChildWithName(ConstString name) {
249+
return UINT32_MAX;
250+
}
251+
252+
SyntheticChildrenFrontEnd *
253+
lldb_private::formatters::swift::UnsafeBufferPointerSyntheticFrontEndCreator(
254+
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
255+
if (!valobj_sp)
256+
return nullptr;
257+
return (new UnsafeBufferPointerSyntheticFrontEnd(valobj_sp));
258+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- SwiftUnsafeTypes.h --------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 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+
#ifndef liblldb_SwiftUnsafeTypes_h_
14+
#define liblldb_SwiftUnsafeTypes_h_
15+
16+
#include "lldb/Core/ValueObject.h"
17+
#include "lldb/Utility/Stream.h"
18+
19+
namespace lldb_private {
20+
namespace formatters {
21+
namespace swift {
22+
23+
bool UnsafeBufferPointerSummaryProvider(ValueObject &valobj, Stream &stream,
24+
const TypeSummaryOptions &);
25+
26+
SyntheticChildrenFrontEnd *
27+
UnsafeBufferPointerSyntheticFrontEndCreator(CXXSyntheticChildren *,
28+
lldb::ValueObjectSP);
29+
30+
}; // namespace swift
31+
}; // namespace formatters
32+
}; // namespace lldb_private
33+
34+
#endif
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
include Makefile.rules
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""
2+
Test that Swift unsafe types get formatted properly
3+
"""
4+
import lldbsuite.test.lldbinline as lldbinline
5+
from lldbsuite.test.decorators import *
6+
7+
lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest])

0 commit comments

Comments
 (0)