Skip to content

Commit 712fc18

Browse files
committed
[lldb] Convert script native types to StructuredData counterpart
This patch adds the ability to pass native types from the script interpreter to methods that use a {SB,}StructuredData argument. To do so, this patch changes the `ScriptedObject` struture that holds the pointer to the script object as well as the originating script interpreter language. It also exposes that to the SB API via a new class called `SBScriptObject`. This structure allows the debugger to parse the script object and convert it to a StructuredData object. If the type is not compatible with the StructuredData types, we will store its pointer in a `StructuredData::Generic` object. This patch also adds some SWIG typemaps that checks the input argument to ensure it's either an SBStructuredData object, in which case it just passes it throught, or a python object that is NOT another SB type, to provide some guardrails for the user. rdar://111467140 Differential Revision: https://reviews.llvm.org/D155161 Signed-off-by: Med Ismail Bennani <[email protected]>
2 parents 9bef315 + f802bcb commit 712fc18

21 files changed

+382
-9
lines changed

lldb/bindings/headers.swig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "lldb/API/SBQueue.h"
5050
#include "lldb/API/SBQueueItem.h"
5151
#include "lldb/API/SBReproducer.h"
52+
#include "lldb/API/SBScriptObject.h"
5253
#include "lldb/API/SBSection.h"
5354
#include "lldb/API/SBSourceManager.h"
5455
#include "lldb/API/SBStream.h"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
%extend lldb::SBScriptObject {
2+
#ifdef SWIGPYTHON
3+
%pythoncode %{
4+
ptr = property(GetPointer, None, doc='''A read only property that returns the underlying script object.''')
5+
lang = property(GetLanguage, None, doc='''A read only property that returns the script language associated with with this script object.''')
6+
%}
7+
#endif
8+
}

lldb/bindings/interfaces.swig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
%include "lldb/API/SBQueue.h"
125125
%include "lldb/API/SBQueueItem.h"
126126
%include "lldb/API/SBReproducer.h"
127+
%include "lldb/API/SBScriptObject.h"
127128
%include "lldb/API/SBSection.h"
128129
%include "lldb/API/SBSourceManager.h"
129130
%include "lldb/API/SBStream.h"
@@ -176,6 +177,7 @@
176177
%include "./interface/SBModuleExtensions.i"
177178
%include "./interface/SBModuleSpecExtensions.i"
178179
%include "./interface/SBProcessExtensions.i"
180+
%include "./interface/SBScriptObjectExtensions.i"
179181
%include "./interface/SBSectionExtensions.i"
180182
%include "./interface/SBStreamExtensions.i"
181183
%include "./interface/SBStringListExtensions.i"

lldb/bindings/python/python-typemaps.swig

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,78 @@
5454
free((char *) $1);
5555
}
5656

57-
%typemap(out) lldb::ScriptedObject {
57+
%typecheck(SWIG_TYPECHECK_POINTER) lldb::ScriptObjectPtr {
58+
PythonObject obj(PyRefType::Borrowed, $input);
59+
if (!obj.IsValid()) {
60+
PyErr_Clear();
61+
$1 = 0;
62+
} else {
63+
$1 = 1;
64+
}
65+
}
66+
67+
%typemap(in) lldb::ScriptObjectPtr {
68+
if ($input == Py_None) {
69+
$1 = nullptr;
70+
} else {
71+
PythonObject obj(PyRefType::Borrowed, $input);
72+
if (!obj.IsValid()) {
73+
PyErr_SetString(PyExc_TypeError, "Script object is not valid");
74+
SWIG_fail;
75+
}
76+
77+
auto lldb_module = PythonModule::Import("lldb");
78+
if (!lldb_module) {
79+
std::string err_msg = llvm::toString(lldb_module.takeError());
80+
PyErr_SetString(PyExc_TypeError, err_msg.c_str());
81+
SWIG_fail;
82+
}
83+
84+
auto sb_structured_data_class = lldb_module.get().Get("SBStructuredData");
85+
if (!sb_structured_data_class) {
86+
std::string err_msg = llvm::toString(sb_structured_data_class.takeError());
87+
PyErr_SetString(PyExc_TypeError, err_msg.c_str());
88+
SWIG_fail;
89+
}
90+
91+
if (obj.IsInstance(sb_structured_data_class.get())) {
92+
$1 = obj.get();
93+
} else {
94+
auto type = obj.GetType();
95+
if (!type) {
96+
std::string err_msg = llvm::toString(type.takeError());
97+
PyErr_SetString(PyExc_TypeError, err_msg.c_str());
98+
SWIG_fail;
99+
}
100+
101+
auto type_name = As<std::string>(type.get().GetAttribute("__name__"));
102+
if (!type_name) {
103+
std::string err_msg = llvm::toString(type_name.takeError());
104+
PyErr_SetString(PyExc_TypeError, err_msg.c_str());
105+
SWIG_fail;
106+
}
107+
108+
if (llvm::StringRef(type_name.get()).startswith("SB")) {
109+
std::string error_msg = "Input type is invalid: " + type_name.get();
110+
PyErr_SetString(PyExc_TypeError, error_msg.c_str());
111+
SWIG_fail;
112+
} else {
113+
$1 = obj.get();
114+
}
115+
}
116+
}
117+
}
118+
119+
%typemap(out) lldb::ScriptObjectPtr {
120+
$result = (PyObject*) $1;
121+
if (!$result)
122+
$result = Py_None;
123+
Py_INCREF($result);
124+
}
125+
126+
%typemap(out) lldb::SBScriptObject {
58127
$result = nullptr;
59-
if (const void* impl = $1)
128+
if (const void* impl = $1.GetPointer())
60129
$result = (PyObject*) impl;
61130
if (!$result) {
62131
$result = Py_None;

lldb/include/lldb/API/SBDebugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ class LLDB_API SBDebugger {
482482
friend class SBListener;
483483
friend class SBProcess;
484484
friend class SBSourceManager;
485+
friend class SBStructuredData;
485486
friend class SBTarget;
486487
friend class SBTrace;
487488

lldb/include/lldb/API/SBDefines.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class LLDB_API SBProcess;
8787
class LLDB_API SBProcessInfo;
8888
class LLDB_API SBQueue;
8989
class LLDB_API SBQueueItem;
90+
class LLDB_API SBScriptObject;
9091
class LLDB_API SBSection;
9192
class LLDB_API SBSourceManager;
9293
class LLDB_API SBStream;
@@ -126,7 +127,6 @@ typedef bool (*SBBreakpointHitCallback)(void *baton, SBProcess &process,
126127
typedef void (*SBDebuggerDestroyCallback)(lldb::user_id_t debugger_id,
127128
void *baton);
128129

129-
typedef void *ScriptedObject;
130-
}
130+
} // namespace lldb
131131

132132
#endif // LLDB_API_SBDEFINES_H

lldb/include/lldb/API/SBProcess.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ class LLDB_API SBProcess {
438438
///
439439
lldb::SBError DeallocateMemory(lldb::addr_t ptr);
440440

441-
lldb::ScriptedObject GetScriptedImplementation();
441+
lldb::SBScriptObject GetScriptedImplementation();
442442

443443
protected:
444444
friend class SBAddress;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===-- SBScriptObject.h ----------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_API_SBSCRIPTOBJECT_H
10+
#define LLDB_API_SBSCRIPTOBJECT_H
11+
12+
#include "lldb/API/SBDefines.h"
13+
14+
namespace lldb_private {
15+
class ScriptObject;
16+
}
17+
18+
namespace lldb {
19+
20+
class LLDB_API SBScriptObject {
21+
public:
22+
SBScriptObject(const ScriptObjectPtr ptr, lldb::ScriptLanguage lang);
23+
24+
SBScriptObject(const lldb::SBScriptObject &rhs);
25+
26+
~SBScriptObject();
27+
28+
const lldb::SBScriptObject &operator=(const lldb::SBScriptObject &rhs);
29+
30+
explicit operator bool() const;
31+
32+
bool operator!=(const SBScriptObject &rhs) const;
33+
34+
bool IsValid() const;
35+
36+
lldb::ScriptObjectPtr GetPointer() const;
37+
38+
lldb::ScriptLanguage GetLanguage() const;
39+
40+
protected:
41+
friend class SBStructuredData;
42+
43+
lldb_private::ScriptObject *get();
44+
45+
lldb_private::ScriptObject &ref();
46+
47+
const lldb_private::ScriptObject &ref() const;
48+
49+
private:
50+
std::unique_ptr<lldb_private::ScriptObject> m_opaque_up;
51+
};
52+
53+
} // namespace lldb
54+
55+
#endif // LLDB_API_SBSCRIPTOBJECT_H

lldb/include/lldb/API/SBStructuredData.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "lldb/API/SBDefines.h"
1313
#include "lldb/API/SBModule.h"
14+
#include "lldb/API/SBScriptObject.h"
1415

1516
namespace lldb_private {
1617
namespace python {
@@ -29,6 +30,9 @@ class SBStructuredData {
2930

3031
SBStructuredData(const lldb::SBStructuredData &rhs);
3132

33+
SBStructuredData(const lldb::SBScriptObject obj,
34+
const lldb::SBDebugger &debugger);
35+
3236
~SBStructuredData();
3337

3438
lldb::SBStructuredData &operator=(const lldb::SBStructuredData &rhs);
@@ -101,6 +105,9 @@ class SBStructuredData {
101105
/// \a dst in all cases.
102106
size_t GetStringValue(char *dst, size_t dst_len) const;
103107

108+
/// Return the generic pointer if this data structure is a generic type.
109+
lldb::SBScriptObject GetGenericValue() const;
110+
104111
protected:
105112
friend class SBAttachInfo;
106113
friend class SBLaunchInfo;

lldb/include/lldb/Core/StructuredDataImpl.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,17 @@ class StructuredDataImpl {
161161
return (::snprintf(dst, dst_len, "%s", result.data()));
162162
}
163163

164+
void *GetGenericValue() const {
165+
if (!m_data_sp)
166+
return nullptr;
167+
168+
StructuredData::Generic *generic_data = m_data_sp->GetAsGeneric();
169+
if (!generic_data)
170+
return nullptr;
171+
172+
return generic_data->GetValue();
173+
}
174+
164175
StructuredData::ObjectSP GetObjectSP() const { return m_data_sp; }
165176

166177
private:

0 commit comments

Comments
 (0)