diff options
Diffstat (limited to 'contrib/llvm-project/lldb/bindings/python')
8 files changed, 2751 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/bindings/python/createPythonInit.py b/contrib/llvm-project/lldb/bindings/python/createPythonInit.py new file mode 100644 index 000000000000..f343832b949b --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/createPythonInit.py @@ -0,0 +1,27 @@ +import os +import sys + +pkgRelDir = sys.argv[1] +pkgFiles = sys.argv[2:] + +getFileName = lambda f: os.path.splitext(os.path.basename(f))[0] +importNames = ", ".join('"{}"'.format(getFileName(f)) for f in pkgFiles) + +script = """__all__ = [{import_names}] +for x in __all__: + __import__('lldb.{pkg_name}.' + x) + +def __lldb_init_module(debugger, internal_dict): + import lldb + for x in __all__: + submodule = getattr(lldb.{pkg_name}, x) + lldb_init = getattr(submodule, '__lldb_init_module', None) + if lldb_init: + lldb_init(debugger, internal_dict) +""".format( + import_names=importNames, pkg_name=pkgRelDir.replace("/", ".") +) + +pkgIniFile = os.path.normpath(os.path.join(pkgRelDir, "__init__.py")) +with open(pkgIniFile, "w") as f: + f.write(script) diff --git a/contrib/llvm-project/lldb/bindings/python/lldb-python b/contrib/llvm-project/lldb/bindings/python/lldb-python new file mode 100755 index 000000000000..3bb3b332d852 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/lldb-python @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 + +import subprocess +import os +import sys +import json + +lldb = os.path.join(os.path.dirname(__file__), 'lldb') + +info_json = subprocess.run([lldb, "-l", "python", "-print-script-interpreter-info"], + check=True, stdout=subprocess.PIPE, encoding='utf8').stdout +info = json.loads(info_json) + +os.environ["PYTHONPATH"] = ( + info["lldb-pythonpath"] + os.path.pathsep + os.environ.get("PYTHONPATH", "")) + +os.execl(info["executable"], info["executable"], *sys.argv[1:]) diff --git a/contrib/llvm-project/lldb/bindings/python/python-extensions.swig b/contrib/llvm-project/lldb/bindings/python/python-extensions.swig new file mode 100644 index 000000000000..4ba1607c7090 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/python-extensions.swig @@ -0,0 +1,607 @@ +%extend lldb::SBBreakpoint { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBBroadcaster { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBCommandReturnObject { + /* the write() and flush() calls are not part of the SB API proper, and are solely for Python usage + they are meant to make an SBCommandReturnObject into a file-like object so that instructions of the sort + print >>sb_command_return_object, "something" + will work correctly */ + + void lldb::SBCommandReturnObject::write (const char* str) + { + if (str) + $self->Printf("%s",str); + } + void lldb::SBCommandReturnObject::flush () + {} +} + +%extend lldb::SBCompileUnit { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBDeclaration { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBFunction { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBLineEntry { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBModule { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBSection { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} +%extend lldb::SBStream { + /* the write() and flush() calls are not part of the SB API proper, and are solely for Python usage + they are meant to make an SBStream into a file-like object so that instructions of the sort + print >>sb_stream, "something" + will work correctly */ + + void lldb::SBStream::write (const char* str) + { + if (str) + $self->Printf("%s",str); + } + void lldb::SBStream::flush () + {} +} +%extend lldb::SBSymbol { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBTarget { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBTypeFilter { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBTypeNameSpecifier { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBTypeSummary { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBTypeSynthetic { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%extend lldb::SBThread { + %pythoncode %{ + def __eq__(self, rhs): + if not isinstance(rhs, type(self)): + return False + + return getattr(_lldb,self.__class__.__name__+"___eq__")(self, rhs) + + def __ne__(self, rhs): + if not isinstance(rhs, type(self)): + return True + + return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs) + %} +} + +%pythoncode %{ + +def command(command_name=None, doc=None): + import lldb + """A decorator function that registers an LLDB command line + command that is bound to the function it is attached to.""" + def callable(function): + """Registers an lldb command for the decorated function.""" + command = "command script add -f %s.%s %s" % (function.__module__, function.__name__, command_name or function.__name__) + lldb.debugger.HandleCommand(command) + if doc: + function.__doc__ = doc + return function + + return callable + +class declaration(object): + '''A class that represents a source declaration location with file, line and column.''' + def __init__(self, file, line, col): + self.file = file + self.line = line + self.col = col + +class value_iter(object): + '''Allows iterating over the children of an :py:class:`SBValue`.''' + def __iter__(self): + return self + + def __next__(self): + if self.index >= self.length: + raise StopIteration() + child_sbvalue = self.sbvalue.GetChildAtIndex(self.index) + self.index += 1 + return value(child_sbvalue) + + def next(self): + return self.__next__() + + def __eq__(self, other): + return not self.__ne__(other) + + def __len__(self): + return self.length + + def __init__(self,value): + self.index = 0 + self.length = 0 + self.sbvalue = value + if type(self.sbvalue) is value: + self.sbvalue = self.sbvalue.sbvalue + self.length = self.sbvalue.GetNumChildren() + +class value(object): + '''Wraps :py:class:`SBValue` objects so the resulting object can be used as a variable would be in code. + + So if you have a Point structure variable in your code in the current frame named "pt", + you can initialize an instance of this class with it: :: + + pt = lldb.value(lldb.frame.FindVariable("pt")) + print pt + print pt.x + print pt.y + + pt = lldb.value(lldb.frame.FindVariable("rectangle_array")) + print rectangle_array[12] + print rectangle_array[5].origin.x''' + def __init__(self, sbvalue): + self.sbvalue = sbvalue + + def __nonzero__(self): + return self.sbvalue.__nonzero__() + + def __bool__(self): + return self.sbvalue.__bool__() + + def __str__(self): + return self.sbvalue.__str__() + + def __getitem__(self, key): + # Allow array access if this value has children... + if type(key) is value: + key = int(key) + if type(key) is int: + child_sbvalue = (self.sbvalue.GetValueForExpressionPath("[%i]" % key)) + if child_sbvalue and child_sbvalue.IsValid(): + return value(child_sbvalue) + raise IndexError("Index '%d' is out of range" % key) + raise TypeError("No array item of type %s" % str(type(key))) + + def __iter__(self): + return value_iter(self.sbvalue) + + def __getattr__(self, name): + child_sbvalue = self.sbvalue.GetChildMemberWithName (name) + if child_sbvalue and child_sbvalue.IsValid(): + return value(child_sbvalue) + raise AttributeError("Attribute '%s' is not defined" % name) + + def __add__(self, other): + return int(self) + int(other) + + def __sub__(self, other): + return int(self) - int(other) + + def __mul__(self, other): + return int(self) * int(other) + + def __floordiv__(self, other): + return int(self) // int(other) + + def __mod__(self, other): + return int(self) % int(other) + + def __divmod__(self, other): + return int(self) % int(other) + + def __pow__(self, other): + return int(self) ** int(other) + + def __lshift__(self, other): + return int(self) << int(other) + + def __rshift__(self, other): + return int(self) >> int(other) + + def __and__(self, other): + return int(self) & int(other) + + def __xor__(self, other): + return int(self) ^ int(other) + + def __or__(self, other): + return int(self) | int(other) + + def __div__(self, other): + return int(self) / int(other) + + def __truediv__(self, other): + return int(self) / int(other) + + def __iadd__(self, other): + result = self.__add__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __isub__(self, other): + result = self.__sub__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __imul__(self, other): + result = self.__mul__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __idiv__(self, other): + result = self.__div__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __itruediv__(self, other): + result = self.__truediv__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __ifloordiv__(self, other): + result = self.__floordiv__(self, other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __imod__(self, other): + result = self.__and__(self, other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __ipow__(self, other): + result = self.__pow__(self, other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __ipow__(self, other, modulo): + result = self.__pow__(self, other, modulo) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __ilshift__(self, other): + result = self.__lshift__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __irshift__(self, other): + result = self.__rshift__(other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __iand__(self, other): + result = self.__and__(self, other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __ixor__(self, other): + result = self.__xor__(self, other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __ior__(self, other): + result = self.__ior__(self, other) + self.sbvalue.SetValueFromCString (str(result)) + return result + + def __neg__(self): + return -int(self) + + def __pos__(self): + return +int(self) + + def __abs__(self): + return abs(int(self)) + + def __invert__(self): + return ~int(self) + + def __complex__(self): + return complex (int(self)) + + def __int__(self): + is_num,is_sign = is_numeric_type(self.sbvalue.GetType().GetCanonicalType().GetBasicType()) + if is_num and not is_sign: return self.sbvalue.GetValueAsUnsigned() + return self.sbvalue.GetValueAsSigned() + + def __long__(self): + return self.__int__() + + def __float__(self): + return float (self.sbvalue.GetValueAsSigned()) + + def __oct__(self): + return '0%o' % self.sbvalue.GetValueAsUnsigned() + + def __hex__(self): + return '0x%x' % self.sbvalue.GetValueAsUnsigned() + + def __len__(self): + return self.sbvalue.GetNumChildren() + + def __eq__(self, other): + if type(other) is int: + return int(self) == other + elif type(other) is str: + return str(self) == other + elif type(other) is value: + self_err = SBError() + other_err = SBError() + self_val = self.sbvalue.GetValueAsUnsigned(self_err) + if self_err.fail: + raise ValueError("unable to extract value of self") + other_val = other.sbvalue.GetValueAsUnsigned(other_err) + if other_err.fail: + raise ValueError("unable to extract value of other") + return self_val == other_val + raise TypeError("Unknown type %s, No equality operation defined." % str(type(other))) + + def __ne__(self, other): + return not self.__eq__(other) +%} + +%pythoncode %{ + +class SBSyntheticValueProvider(object): + def __init__(self,valobj): + pass + + def num_children(self): + return 0 + + def get_child_index(self,name): + return None + + def get_child_at_index(self,idx): + return None + + def update(self): + pass + + def has_children(self): + return False + + def __len__(self): + return self.num_children() + + def __iter__(self): + '''Iterate over all children in a lldb.SBSyntheticValueProvider object.''' + return lldb_iter(self, 'num_children', 'get_child_at_index') + +%} + +%pythoncode %{ + +# given an lldb.SBBasicType it returns a tuple +# (is_numeric, is_signed) +# the value of is_signed is undefined if is_numeric == false +def is_numeric_type(basic_type): + if basic_type == eBasicTypeInvalid: return (False,False) + if basic_type == eBasicTypeVoid: return (False,False) + if basic_type == eBasicTypeChar: return (True,False) + if basic_type == eBasicTypeSignedChar: return (True,True) + if basic_type == eBasicTypeUnsignedChar: return (True,False) + if basic_type == eBasicTypeWChar: return (True,False) + if basic_type == eBasicTypeSignedWChar: return (True,True) + if basic_type == eBasicTypeUnsignedWChar: return (True,False) + if basic_type == eBasicTypeChar16: return (True,False) + if basic_type == eBasicTypeChar32: return (True,False) + if basic_type == eBasicTypeChar8: return (True,False) + if basic_type == eBasicTypeShort: return (True,True) + if basic_type == eBasicTypeUnsignedShort: return (True,False) + if basic_type == eBasicTypeInt: return (True,True) + if basic_type == eBasicTypeUnsignedInt: return (True,False) + if basic_type == eBasicTypeLong: return (True,True) + if basic_type == eBasicTypeUnsignedLong: return (True,False) + if basic_type == eBasicTypeLongLong: return (True,True) + if basic_type == eBasicTypeUnsignedLongLong: return (True,False) + if basic_type == eBasicTypeInt128: return (True,True) + if basic_type == eBasicTypeUnsignedInt128: return (True,False) + if basic_type == eBasicTypeBool: return (False,False) + if basic_type == eBasicTypeHalf: return (True,True) + if basic_type == eBasicTypeFloat: return (True,True) + if basic_type == eBasicTypeDouble: return (True,True) + if basic_type == eBasicTypeLongDouble: return (True,True) + if basic_type == eBasicTypeFloatComplex: return (True,True) + if basic_type == eBasicTypeDoubleComplex: return (True,True) + if basic_type == eBasicTypeLongDoubleComplex: return (True,True) + if basic_type == eBasicTypeObjCID: return (False,False) + if basic_type == eBasicTypeObjCClass: return (False,False) + if basic_type == eBasicTypeObjCSel: return (False,False) + if basic_type == eBasicTypeNullPtr: return (False,False) + #if basic_type == eBasicTypeOther: + return (False,False) + +%} diff --git a/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig b/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig new file mode 100644 index 000000000000..34f8c6f0ff8d --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig @@ -0,0 +1,137 @@ +namespace lldb_private { +namespace python { + +PythonObject ToSWIGHelper(void *obj, swig_type_info *info) { + return {PyRefType::Owned, SWIG_NewPointerObj(obj, info, SWIG_POINTER_OWN)}; +} + +PythonObject SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBValue> value_sb) { + return ToSWIGHelper(value_sb.release(), SWIGTYPE_p_lldb__SBValue); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::ValueObjectSP value_sp) { + return ToSWIGWrapper(std::unique_ptr<lldb::SBValue>(new lldb::SBValue(value_sp))); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::TargetSP target_sp) { + return ToSWIGHelper(new lldb::SBTarget(std::move(target_sp)), + SWIGTYPE_p_lldb__SBTarget); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::ProcessSP process_sp) { + return ToSWIGHelper(new lldb::SBProcess(std::move(process_sp)), + SWIGTYPE_p_lldb__SBProcess); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::ThreadPlanSP thread_plan_sp) { + return ToSWIGHelper(new lldb::SBThreadPlan(std::move(thread_plan_sp)), + SWIGTYPE_p_lldb__SBThreadPlan); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp) { + return ToSWIGHelper(new lldb::SBBreakpoint(std::move(breakpoint_sp)), + SWIGTYPE_p_lldb__SBBreakpoint); +} + +PythonObject SWIGBridge::ToSWIGWrapper(const Status& status) { + return ToSWIGHelper(new lldb::SBError(status), SWIGTYPE_p_lldb__SBError); +} + +PythonObject SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb) { + return ToSWIGHelper(data_sb.release(), SWIGTYPE_p_lldb__SBStructuredData); +} + +PythonObject SWIGBridge::ToSWIGWrapper(const StructuredDataImpl &data_impl) { + return ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData>(new lldb::SBStructuredData(data_impl))); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::ThreadSP thread_sp) { + return ToSWIGHelper(new lldb::SBThread(std::move(thread_sp)), + SWIGTYPE_p_lldb__SBThread); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::StackFrameSP frame_sp) { + return ToSWIGHelper(new lldb::SBFrame(std::move(frame_sp)), + SWIGTYPE_p_lldb__SBFrame); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::DebuggerSP debugger_sp) { + return ToSWIGHelper(new lldb::SBDebugger(std::move(debugger_sp)), + SWIGTYPE_p_lldb__SBDebugger); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::WatchpointSP watchpoint_sp) { + return ToSWIGHelper(new lldb::SBWatchpoint(std::move(watchpoint_sp)), + SWIGTYPE_p_lldb__SBWatchpoint); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::BreakpointLocationSP bp_loc_sp) { + return ToSWIGHelper(new lldb::SBBreakpointLocation(std::move(bp_loc_sp)), + SWIGTYPE_p_lldb__SBBreakpointLocation); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp) { + return ToSWIGHelper(new lldb::SBExecutionContext(std::move(ctx_sp)), + SWIGTYPE_p_lldb__SBExecutionContext); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::TypeImplSP type_impl_sp) { + return ToSWIGHelper(new lldb::SBType(type_impl_sp), SWIGTYPE_p_lldb__SBType); +} + +PythonObject SWIGBridge::ToSWIGWrapper(const TypeSummaryOptions &summary_options) { + return ToSWIGHelper(new lldb::SBTypeSummaryOptions(summary_options), + SWIGTYPE_p_lldb__SBTypeSummaryOptions); +} + +PythonObject SWIGBridge::ToSWIGWrapper(const SymbolContext &sym_ctx) { + return ToSWIGHelper(new lldb::SBSymbolContext(sym_ctx), + SWIGTYPE_p_lldb__SBSymbolContext); +} + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp) { + return ToSWIGHelper(new lldb::ProcessLaunchInfoSP(std::move(launch_info_sp)), + SWIGTYPE_p_lldb__SBLaunchInfo); + } + + PythonObject SWIGBridge::ToSWIGWrapper(lldb::ProcessAttachInfoSP attach_info_sp) { + return ToSWIGHelper(new lldb::ProcessAttachInfoSP(std::move(attach_info_sp)), + SWIGTYPE_p_lldb__SBAttachInfo); + } + +PythonObject SWIGBridge::ToSWIGWrapper(lldb::DataExtractorSP data_sp) { + return ToSWIGHelper(new lldb::DataExtractorSP(std::move(data_sp)), + SWIGTYPE_p_lldb__SBData); +} + +ScopedPythonObject<lldb::SBCommandReturnObject> +SWIGBridge::ToSWIGWrapper(CommandReturnObject &cmd_retobj) { + return ScopedPythonObject<lldb::SBCommandReturnObject>( + new lldb::SBCommandReturnObject(cmd_retobj), + SWIGTYPE_p_lldb__SBCommandReturnObject); +} + +PythonObject SWIGBridge::ToSWIGWrapper(const Stream *s) { + return ToSWIGHelper(new lldb::SBStream(), SWIGTYPE_p_lldb__SBStream); +} + +PythonObject SWIGBridge::ToSWIGWrapper(std::shared_ptr<lldb::SBStream> stream_sb) { + return ToSWIGHelper(stream_sb.get(), SWIGTYPE_p_lldb__SBStream); +} + +PythonObject SWIGBridge::ToSWIGWrapper(Event *event) { + return ToSWIGHelper(new lldb::SBEvent(event), SWIGTYPE_p_lldb__SBEvent); +} + +PythonObject SWIGBridge::ToSWIGWrapper( + std::unique_ptr<lldb::SBFileSpec> file_spec_sb) { + return ToSWIGHelper(file_spec_sb.release(), SWIGTYPE_p_lldb__SBFileSpec); +} + +PythonObject SWIGBridge::ToSWIGWrapper( + std::unique_ptr<lldb::SBModuleSpec> module_spec_sb) { + return ToSWIGHelper(module_spec_sb.release(), SWIGTYPE_p_lldb__SBModuleSpec); +} + +} // namespace python +} // namespace lldb_private diff --git a/contrib/llvm-project/lldb/bindings/python/python-typemaps.h b/contrib/llvm-project/lldb/bindings/python/python-typemaps.h new file mode 100644 index 000000000000..8a533e822988 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/python-typemaps.h @@ -0,0 +1,19 @@ +#ifndef LLDB_BINDINGS_PYTHON_PYTHON_TYPEMAPS_H +#define LLDB_BINDINGS_PYTHON_PYTHON_TYPEMAPS_H + +#include <Python.h> + +// Defined here instead of a .swig file because SWIG 2 doesn't support +// explicit deleted functions. +struct Py_buffer_RAII { + Py_buffer buffer = {}; + Py_buffer_RAII(){}; + Py_buffer &operator=(const Py_buffer_RAII &) = delete; + Py_buffer_RAII(const Py_buffer_RAII &) = delete; + ~Py_buffer_RAII() { + if (buffer.obj) + PyBuffer_Release(&buffer); + } +}; + +#endif // LLDB_BINDINGS_PYTHON_PYTHON_TYPEMAPS_H diff --git a/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig b/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig new file mode 100644 index 000000000000..f8c33e15c03e --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig @@ -0,0 +1,715 @@ +/* Typemap definitions, to allow SWIG to properly handle 'char**' data types. + +NOTE: If there's logic to free memory in a %typemap(freearg), it will also be +run if you call SWIG_fail on an error path. Don't manually free() an argument +AND call SWIG_fail at the same time, because it will result in a double free. + +*/ + +%inline %{ + +#include "../bindings/python/python-typemaps.h" + +%} + +%typemap(in) char ** { + /* Check if is a list */ + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); + int i = 0; + $1 = (char **)malloc((size + 1) * sizeof(char *)); + for (i = 0; i < size; i++) { + PythonString py_str = list.GetItemAtIndex(i).AsType<PythonString>(); + if (!py_str.IsAllocated()) { + PyErr_SetString(PyExc_TypeError, "list must contain strings"); + SWIG_fail; + } + + $1[i] = const_cast<char *>(py_str.GetString().data()); + } + $1[i] = 0; + } else if ($input == Py_None) { + $1 = NULL; + } else { + PyErr_SetString(PyExc_TypeError, "not a list"); + SWIG_fail; + } +} + +%typemap(typecheck) char ** { + /* Check if is a list */ + $1 = 1; + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + int size = list.GetSize(); + int i = 0; + for (i = 0; i < size; i++) { + PythonString s = list.GetItemAtIndex(i).AsType<PythonString>(); + if (!s.IsAllocated()) { + $1 = 0; + } + } + } else { + $1 = (($input == Py_None) ? 1 : 0); + } +} + +%typemap(freearg) char** { + free((char *) $1); +} + +%typecheck(SWIG_TYPECHECK_POINTER) lldb::ScriptObjectPtr { + PythonObject obj(PyRefType::Borrowed, $input); + if (!obj.IsValid()) { + PyErr_Clear(); + $1 = 0; + } else { + $1 = 1; + } +} + +%typemap(in) lldb::ScriptObjectPtr { + if ($input == Py_None) { + $1 = nullptr; + } else { + PythonObject obj(PyRefType::Borrowed, $input); + if (!obj.IsValid()) { + PyErr_SetString(PyExc_TypeError, "Script object is not valid"); + SWIG_fail; + } + + auto lldb_module = PythonModule::Import("lldb"); + if (!lldb_module) { + std::string err_msg = llvm::toString(lldb_module.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + auto sb_structured_data_class = lldb_module.get().Get("SBStructuredData"); + if (!sb_structured_data_class) { + std::string err_msg = llvm::toString(sb_structured_data_class.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + if (obj.IsInstance(sb_structured_data_class.get())) { + $1 = obj.get(); + } else { + auto type = obj.GetType(); + if (!type) { + std::string err_msg = llvm::toString(type.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + auto type_name = As<std::string>(type.get().GetAttribute("__name__")); + if (!type_name) { + std::string err_msg = llvm::toString(type_name.takeError()); + PyErr_SetString(PyExc_TypeError, err_msg.c_str()); + SWIG_fail; + } + + if (llvm::StringRef(type_name.get()).starts_with("SB")) { + std::string error_msg = "Input type is invalid: " + type_name.get(); + PyErr_SetString(PyExc_TypeError, error_msg.c_str()); + SWIG_fail; + } else { + $1 = obj.get(); + } + } + } +} + +%typemap(out) lldb::ScriptObjectPtr { + $result = (PyObject*) $1; + if (!$result) + $result = Py_None; + Py_INCREF($result); +} + +%typemap(out) lldb::SBScriptObject { + $result = nullptr; + if (const void* impl = $1.GetPointer()) + $result = (PyObject*) impl; + if (!$result) { + $result = Py_None; + Py_INCREF(Py_None); + } else { + Py_INCREF($result); + } +} + +%typemap(out) char** { + int len; + int i; + len = 0; + while ($1[len]) + len++; + PythonList list(len); + for (i = 0; i < len; i++) + list.SetItemAtIndex(i, PythonString($1[i])); + $result = list.release(); +} + +%typemap(in) lldb::tid_t { + PythonObject obj = Retain<PythonObject>($input); + lldb::tid_t value = unwrapOrSetPythonException(As<unsigned long long>(obj)); + if (PyErr_Occurred()) + SWIG_fail; + $1 = value; +} + +%typemap(in) lldb::StateType { + PythonObject obj = Retain<PythonObject>($input); + unsigned long long state_type_value = + unwrapOrSetPythonException(As<unsigned long long>(obj)); + if (PyErr_Occurred()) + SWIG_fail; + if (state_type_value > lldb::StateType::kLastStateType) { + PyErr_SetString(PyExc_ValueError, "Not a valid StateType value"); + SWIG_fail; + } + $1 = static_cast<lldb::StateType>(state_type_value); +} + +/* Typemap definitions to allow SWIG to properly handle char buffer. */ + +// typemap for a char buffer +%typemap(in) (char *dst, size_t dst_len) { + if (!PyLong_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + SWIG_fail; + } + $2 = PyLong_AsLong($input); + if ($2 <= 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + SWIG_fail; + } + $1 = (char *)malloc($2); +} +// SBProcess::ReadCStringFromMemory() uses a void*, but needs to be treated +// as char data instead of byte data. +%typemap(in) (void *char_buf, size_t size) = (char *dst, size_t dst_len); + +// Return the char buffer. Discarding any previous return result +%typemap(argout) (char *dst, size_t dst_len) { + Py_XDECREF($result); /* Blow away any previous result */ + if (result == 0) { + PythonString string(""); + $result = string.release(); + Py_INCREF($result); + } else { + llvm::StringRef ref(static_cast<const char *>($1), result); + PythonString string(ref); + $result = string.release(); + } + free($1); +} +// SBProcess::ReadCStringFromMemory() uses a void*, but needs to be treated +// as char data instead of byte data. +%typemap(argout) (void *char_buf, size_t size) = (char *dst, size_t dst_len); + + +// typemap for handling an snprintf-like API like SBThread::GetStopDescription. +%typemap(in) (char *dst_or_null, size_t dst_len) { + if (!PyLong_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + SWIG_fail; + } + $2 = PyLong_AsLong($input); + if ($2 <= 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + SWIG_fail; + } + $1 = (char *)malloc($2); +} +%typemap(argout) (char *dst_or_null, size_t dst_len) { + Py_XDECREF($result); /* Blow away any previous result */ + llvm::StringRef ref($1); + PythonString string(ref); + $result = string.release(); + free($1); +} + + +// typemap for an outgoing buffer +// See also SBEvent::SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len). +// Ditto for SBProcess::PutSTDIN(const char *src, size_t src_len). +%typemap(in) (const char *cstr, uint32_t cstr_len), + (const char *src, size_t src_len) { + if (PythonString::Check($input)) { + PythonString str(PyRefType::Borrowed, $input); + $1 = (char *)str.GetString().data(); + $2 = str.GetSize(); + } else if (PythonByteArray::Check($input)) { + PythonByteArray bytearray(PyRefType::Borrowed, $input); + $1 = (char *)bytearray.GetBytes().data(); + $2 = bytearray.GetSize(); + } else if (PythonBytes::Check($input)) { + PythonBytes bytes(PyRefType::Borrowed, $input); + $1 = (char *)bytes.GetBytes().data(); + $2 = bytes.GetSize(); + } else { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + SWIG_fail; + } +} +// For SBProcess::WriteMemory, SBTarget::GetInstructions and SBDebugger::DispatchInput. +%typemap(in) (const void *buf, size_t size), + (const void *data, size_t data_len), + (const void *buf, uint64_t size) { + if (PythonString::Check($input)) { + PythonString str(PyRefType::Borrowed, $input); + $1 = (void *)str.GetString().data(); + $2 = str.GetSize(); + } else if (PythonByteArray::Check($input)) { + PythonByteArray bytearray(PyRefType::Borrowed, $input); + $1 = (void *)bytearray.GetBytes().data(); + $2 = bytearray.GetSize(); + } else if (PythonBytes::Check($input)) { + PythonBytes bytes(PyRefType::Borrowed, $input); + $1 = (void *)bytes.GetBytes().data(); + $2 = bytes.GetSize(); + } else { + PyErr_SetString(PyExc_ValueError, "Expecting a buffer"); + SWIG_fail; + } +} + +// typemap for an incoming buffer +// See also SBProcess::ReadMemory. +%typemap(in) (void *buf, size_t size) { + if (PyLong_Check($input)) { + $2 = PyLong_AsLong($input); + } else { + PyErr_SetString(PyExc_ValueError, "Expecting an integer or long object"); + SWIG_fail; + } + if ($2 <= 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + SWIG_fail; + } + $1 = (void *)malloc($2); +} + +// Return the buffer. Discarding any previous return result +// See also SBProcess::ReadMemory. +%typemap(argout) (void *buf, size_t size) { + Py_XDECREF($result); /* Blow away any previous result */ + if (result == 0) { + $result = Py_None; + Py_INCREF($result); + } else { + PythonBytes bytes(static_cast<const uint8_t *>($1), result); + $result = bytes.release(); + } + free($1); +} + +%{ +namespace { +template <class T> +T PyLongAsT(PyObject *obj) { + static_assert(true, "unsupported type"); +} + +template <> uint64_t PyLongAsT<uint64_t>(PyObject *obj) { + return static_cast<uint64_t>(PyLong_AsUnsignedLongLong(obj)); +} + +template <> uint32_t PyLongAsT<uint32_t>(PyObject *obj) { + return static_cast<uint32_t>(PyLong_AsUnsignedLong(obj)); +} + +template <> int64_t PyLongAsT<int64_t>(PyObject *obj) { + return static_cast<int64_t>(PyLong_AsLongLong(obj)); +} + +template <> int32_t PyLongAsT<int32_t>(PyObject *obj) { + return static_cast<int32_t>(PyLong_AsLong(obj)); +} + +template <class T> bool SetNumberFromPyObject(T &number, PyObject *obj) { + if (PyLong_Check(obj)) + number = PyLongAsT<T>(obj); + else + return false; + + return true; +} + +template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) { + if (PyFloat_Check(obj)) { + number = PyFloat_AsDouble(obj); + return true; + } + + return false; +} + +} // namespace +%} + +// these typemaps allow Python users to pass list objects +// and have them turn into C++ arrays (this is useful, for instance +// when creating SBData objects from lists of numbers) +%typemap(in) (uint64_t* array, size_t array_len), + (uint32_t* array, size_t array_len), + (int64_t* array, size_t array_len), + (int32_t* array, size_t array_len), + (double* array, size_t array_len) { + /* Check if is a list */ + if (PyList_Check($input)) { + int size = PyList_Size($input); + int i = 0; + $2 = size; + $1 = ($1_type)malloc(size * sizeof($*1_type)); + for (i = 0; i < size; i++) { + PyObject *o = PyList_GetItem($input, i); + if (!SetNumberFromPyObject($1[i], o)) { + PyErr_SetString(PyExc_TypeError, "list must contain numbers"); + SWIG_fail; + } + + if (PyErr_Occurred()) { + SWIG_fail; + } + } + } else if ($input == Py_None) { + $1 = NULL; + $2 = 0; + } else { + PyErr_SetString(PyExc_TypeError, "not a list"); + SWIG_fail; + } +} + +%typemap(freearg) (uint64_t* array, size_t array_len), + (uint32_t* array, size_t array_len), + (int64_t* array, size_t array_len), + (int32_t* array, size_t array_len), + (double* array, size_t array_len) { + free($1); +} + +// these typemaps wrap SBModule::GetVersion() from requiring a memory buffer +// to the more Pythonic style where a list is returned and no previous allocation +// is necessary - this will break if more than 50 versions are ever returned +%typemap(typecheck) (uint32_t *versions, uint32_t num_versions) { + $1 = ($input == Py_None ? 1 : 0); +} + +%typemap(in, numinputs=0) (uint32_t *versions) { + $1 = (uint32_t *)malloc(sizeof(uint32_t) * 50); +} + +%typemap(in, numinputs=0) (uint32_t num_versions) { + $1 = 50; +} + +%typemap(argout) (uint32_t *versions, uint32_t num_versions) { + uint32_t count = result; + if (count >= $2) + count = $2; + PyObject *list = PyList_New(count); + for (uint32_t j = 0; j < count; j++) { + PyObject *item = PyLong_FromLong($1[j]); + int ok = PyList_SetItem(list, j, item); + if (ok != 0) { + $result = Py_None; + break; + } + } + $result = list; +} + +%typemap(freearg) (uint32_t *versions) { + free($1); +} + +// For Log::LogOutputCallback +%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) { + if (!($input == Py_None || + PyCallable_Check(reinterpret_cast<PyObject *>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + SWIG_fail; + } + + // FIXME (filcab): We can't currently check if our callback is already + // LLDBSwigPythonCallPythonLogOutputCallback (to DECREF the previous + // baton) nor can we just remove all traces of a callback, if we want to + // revert to a file logging mechanism. + + // Don't lose the callback reference + Py_INCREF($input); + $1 = LLDBSwigPythonCallPythonLogOutputCallback; + $2 = $input; +} + +%typemap(typecheck) (lldb::LogOutputCallback log_callback, void *baton) { + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); +} + +// For lldb::SBDebuggerDestroyCallback +%typemap(in) (lldb::SBDebuggerDestroyCallback destroy_callback, void *baton) { + if (!($input == Py_None || + PyCallable_Check(reinterpret_cast<PyObject *>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + SWIG_fail; + } + + // FIXME (filcab): We can't currently check if our callback is already + // LLDBSwigPythonCallPythonSBDebuggerTerminateCallback (to DECREF the previous + // baton) nor can we just remove all traces of a callback, if we want to + // revert to a file logging mechanism. + + // Don't lose the callback reference + Py_INCREF($input); + $1 = LLDBSwigPythonCallPythonSBDebuggerTerminateCallback; + $2 = $input; +} + +%typemap(typecheck) (lldb::SBDebuggerDestroyCallback destroy_callback, void *baton) { + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); +} + +%typemap(in) (lldb::CommandOverrideCallback callback, void *baton) { + if (!($input == Py_None || + PyCallable_Check(reinterpret_cast<PyObject *>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + SWIG_fail; + } + + // Don't lose the callback reference. + Py_INCREF($input); + $1 = LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback; + $2 = $input; +} +%typemap(typecheck) (lldb::CommandOverrideCallback callback, void *baton) { + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); +} + +%typemap(in) lldb::FileSP { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + SWIG_fail; + } + auto sp = unwrapOrSetPythonException(py_file.ConvertToFile()); + if (!sp) + SWIG_fail; + $1 = sp; +} + +%typemap(in) lldb::FileSP FORCE_IO_METHODS { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + SWIG_fail; + } + auto sp = unwrapOrSetPythonException( + py_file.ConvertToFileForcingUseOfScriptingIOMethods()); + if (!sp) + SWIG_fail; + $1 = sp; +} + +%typemap(in) lldb::FileSP BORROWED { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + SWIG_fail; + } + auto sp = + unwrapOrSetPythonException(py_file.ConvertToFile(/*borrowed=*/true)); + if (!sp) + SWIG_fail; + $1 = sp; +} + +%typemap(in) lldb::FileSP BORROWED_FORCE_IO_METHODS { + PythonFile py_file(PyRefType::Borrowed, $input); + if (!py_file) { + PyErr_SetString(PyExc_TypeError, "not a file"); + SWIG_fail; + } + auto sp = unwrapOrSetPythonException( + py_file.ConvertToFileForcingUseOfScriptingIOMethods(/*borrowed=*/true)); + if (!sp) + SWIG_fail; + $1 = sp; +} + +%typecheck(SWIG_TYPECHECK_POINTER) lldb::FileSP { + if (PythonFile::Check($input)) { + $1 = 1; + } else { + PyErr_Clear(); + $1 = 0; + } +} + +%typemap(out) lldb::FileSP { + $result = nullptr; + const lldb::FileSP &sp = $1; + if (sp) { + PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp)); + if (!pyfile.IsValid()) + SWIG_fail; + $result = pyfile.release(); + } + if (!$result) { + $result = Py_None; + Py_INCREF(Py_None); + } +} + +%typemap(in) (const char* string, int len) { + if ($input == Py_None) { + $1 = NULL; + $2 = 0; + } else if (PythonString::Check($input)) { + PythonString py_str(PyRefType::Borrowed, $input); + llvm::StringRef str = py_str.GetString(); + $1 = const_cast<char *>(str.data()); + $2 = str.size(); + // In Python 2, if $input is a PyUnicode object then this + // will trigger a Unicode -> String conversion, in which + // case the `PythonString` will now own the PyString. Thus + // if it goes out of scope, the data will be deleted. The + // only way to avoid this is to leak the Python object in + // that case. Note that if there was no conversion, then + // releasing the string will not leak anything, since we + // created this as a borrowed reference. + py_str.release(); + } else { + PyErr_SetString(PyExc_TypeError, "not a string-like object"); + SWIG_fail; + } +} + +// These two pybuffer macros are copied out of swig/Lib/python/pybuffer.i, +// and fixed so they will not crash if PyObject_GetBuffer fails. +// https://github.com/swig/swig/issues/1640 +// +// I've also moved the call to PyBuffer_Release to the end of the SWIG wrapper, +// doing it right away is not legal according to the python buffer protocol. + +%define %pybuffer_mutable_binary(TYPEMAP, SIZE) +%typemap(in) (TYPEMAP, SIZE) (Py_buffer_RAII view) { + int res; + Py_ssize_t size = 0; + void *buf = 0; + res = PyObject_GetBuffer($input, &view.buffer, PyBUF_WRITABLE); + if (res < 0) { + PyErr_Clear(); + %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); + } + size = view.buffer.len; + buf = view.buffer.buf; + $1 = ($1_ltype)buf; + $2 = ($2_ltype)(size / sizeof($*1_type)); +} +%enddef + +%define %pybuffer_binary(TYPEMAP, SIZE) +%typemap(in) (TYPEMAP, SIZE) (Py_buffer_RAII view) { + int res; + Py_ssize_t size = 0; + const void *buf = 0; + res = PyObject_GetBuffer($input, &view.buffer, PyBUF_CONTIG_RO); + if (res < 0) { + PyErr_Clear(); + %argument_fail(res, "(TYPEMAP, SIZE)", $symname, $argnum); + } + size = view.buffer.len; + buf = view.buffer.buf; + $1 = ($1_ltype)buf; + $2 = ($2_ltype)(size / sizeof($*1_type)); +} +%enddef + +%pybuffer_binary(const uint8_t *buf, size_t num_bytes); +%pybuffer_mutable_binary(uint8_t *buf, size_t num_bytes); + +%typemap(in) (const char **symbol_name, uint32_t num_names) { + using namespace lldb_private; + /* Check if is a list */ + if (PythonList::Check($input)) { + PythonList list(PyRefType::Borrowed, $input); + $2 = list.GetSize(); + int i = 0; + $1 = (char**)malloc(($2+1)*sizeof(char*)); + for (i = 0; i < $2; i++) { + PythonString py_str = list.GetItemAtIndex(i).AsType<PythonString>(); + if (!py_str.IsAllocated()) { + PyErr_SetString(PyExc_TypeError,"list must contain strings and blubby"); + free($1); + return nullptr; + } + + $1[i] = const_cast<char*>(py_str.GetString().data()); + } + $1[i] = 0; + } else if ($input == Py_None) { + $1 = NULL; + } else { + PyErr_SetString(PyExc_TypeError,"not a list"); + return NULL; + } +} + +// For lldb::SBPlatformLocateModuleCallback +%typemap(in) (lldb::SBPlatformLocateModuleCallback callback, + void *callback_baton) { + if (!($input == Py_None || + PyCallable_Check(reinterpret_cast<PyObject *>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + SWIG_fail; + } + + if ($input == Py_None) { + $1 = nullptr; + $2 = nullptr; + } else { + PythonCallable callable = Retain<PythonCallable>($input); + if (!callable.IsValid()) { + PyErr_SetString(PyExc_TypeError, "Need a valid callable object"); + SWIG_fail; + } + + llvm::Expected<PythonCallable::ArgInfo> arg_info = callable.GetArgInfo(); + if (!arg_info) { + PyErr_SetString(PyExc_TypeError, + ("Could not get arguments: " + + llvm::toString(arg_info.takeError())).c_str()); + SWIG_fail; + } + + if (arg_info.get().max_positional_args != 3) { + PyErr_SetString(PyExc_TypeError, "Expected 3 argument callable object"); + SWIG_fail; + } + + // NOTE: When this is called multiple times, this will leak the Python + // callable object as other callbacks, because this does not call Py_DECREF + // the object. But it should be almost zero impact since this method is + // expected to be called only once. + + // Don't lose the callback reference + Py_INCREF($input); + + $1 = LLDBSwigPythonCallLocateModuleCallback; + $2 = $input; + } +} + +%typemap(typecheck) (lldb::SBPlatformLocateModuleCallback callback, + void *callback_baton) { + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); +} diff --git a/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig b/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig new file mode 100644 index 000000000000..8f050643fa68 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig @@ -0,0 +1,1092 @@ +%header %{ + +class PyErr_Cleaner { +public: + PyErr_Cleaner(bool print = false) : m_print(print) {} + + ~PyErr_Cleaner() { + if (PyErr_Occurred()) { + if (m_print && !PyErr_ExceptionMatches(PyExc_SystemExit)) + PyErr_Print(); + PyErr_Clear(); + } + } + +private: + bool m_print; +}; + +llvm::Expected<bool> lldb_private::python::SWIGBridge::LLDBSwigPythonBreakpointCallbackFunction( + const char *python_function_name, const char *session_dictionary_name, + const lldb::StackFrameSP &frame_sp, + const lldb::BreakpointLocationSP &bp_loc_sp, + const lldb_private::StructuredDataImpl &args_impl) { + using namespace llvm; + + lldb::SBBreakpointLocation sb_bp_loc(bp_loc_sp); + + PyErr_Cleaner py_err_cleaner(true); + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + unsigned max_positional_args; + if (auto arg_info = pfunc.GetArgInfo()) + max_positional_args = arg_info.get().max_positional_args; + else + return arg_info.takeError(); + + PythonObject frame_arg = SWIGBridge::ToSWIGWrapper(frame_sp); + PythonObject bp_loc_arg = SWIGBridge::ToSWIGWrapper(bp_loc_sp); + + auto result = + max_positional_args < 4 + ? pfunc.Call(frame_arg, bp_loc_arg, dict) + : pfunc.Call(frame_arg, bp_loc_arg, SWIGBridge::ToSWIGWrapper(args_impl), dict); + + if (!result) + return result.takeError(); + + // Only False counts as false! + return result.get().get() != Py_False; +} + +// resolve a dotted Python name in the form +// foo.bar.baz.Foobar to an actual Python object +// if pmodule is NULL, the __main__ module will be used +// as the starting point for the search + +// This function is called by +// lldb_private::ScriptInterpreterPython::BreakpointCallbackFunction(...) and is +// used when a script command is attached to a breakpoint for execution. + +// This function is called by +// lldb_private::ScriptInterpreterPython::WatchpointCallbackFunction(...) and is +// used when a script command is attached to a watchpoint for execution. + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonWatchpointCallbackFunction( + const char *python_function_name, const char *session_dictionary_name, + const lldb::StackFrameSP &frame_sp, const lldb::WatchpointSP &wp_sp) { + + bool stop_at_watchpoint = true; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return stop_at_watchpoint; + + PythonObject result = + pfunc(SWIGBridge::ToSWIGWrapper(frame_sp), SWIGBridge::ToSWIGWrapper(wp_sp), dict); + + if (result.get() == Py_False) + stop_at_watchpoint = false; + + return stop_at_watchpoint; +} + +// This function is called by +// ScriptInterpreterPython::FormatterMatchingCallbackFunction and it's used when +// a data formatter provides the name of a callback to inspect a candidate type +// before considering a match. +bool lldb_private::python::SWIGBridge::LLDBSwigPythonFormatterCallbackFunction( + const char *python_function_name, const char *session_dictionary_name, + lldb::TypeImplSP type_impl_sp) { + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return false; + + PythonObject result = + pfunc(SWIGBridge::ToSWIGWrapper(type_impl_sp), dict); + + // Only if everything goes okay and the function returns True we'll consider + // it a match. + return result.get() == Py_True; +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallTypeScript( + const char *python_function_name, const void *session_dictionary, + const lldb::ValueObjectSP &valobj_sp, void **pyfunct_wrapper, + const lldb::TypeSummaryOptionsSP &options_sp, std::string &retval) { + + retval.clear(); + + if (!python_function_name || !session_dictionary) + return false; + + PyObject *pfunc_impl = nullptr; + + if (pyfunct_wrapper && *pyfunct_wrapper && + PyFunction_Check(*pyfunct_wrapper)) { + pfunc_impl = (PyObject *)(*pyfunct_wrapper); + if (pfunc_impl->ob_refcnt == 1) { + Py_XDECREF(pfunc_impl); + pfunc_impl = NULL; + } + } + + PyObject *py_dict = (PyObject *)session_dictionary; + if (!PythonDictionary::Check(py_dict)) + return true; + + PythonDictionary dict(PyRefType::Borrowed, py_dict); + + PyErr_Cleaner pyerr_cleanup(true); // show Python errors + + PythonCallable pfunc(PyRefType::Borrowed, pfunc_impl); + + if (!pfunc.IsAllocated()) { + pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + if (!pfunc.IsAllocated()) + return false; + + if (pyfunct_wrapper) { + *pyfunct_wrapper = pfunc.get(); + Py_XINCREF(pfunc.get()); + } + } + + PythonObject result; + auto argc = pfunc.GetArgInfo(); + if (!argc) { + llvm::consumeError(argc.takeError()); + return false; + } + + PythonObject value_arg = SWIGBridge::ToSWIGWrapper(valobj_sp); + + if (argc.get().max_positional_args < 3) + result = pfunc(value_arg, dict); + else + result = pfunc(value_arg, dict, SWIGBridge::ToSWIGWrapper(*options_sp)); + + retval = result.Str().GetString().str(); + + return true; +} + +PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateSyntheticProvider( + const char *python_class_name, const char *session_dictionary_name, + const lldb::ValueObjectSP &valobj_sp) { + if (python_class_name == NULL || python_class_name[0] == '\0' || + !session_dictionary_name) + return PythonObject(); + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_class_name, dict); + + if (!pfunc.IsAllocated()) + return PythonObject(); + + auto sb_value = std::unique_ptr<lldb::SBValue>(new lldb::SBValue(valobj_sp)); + sb_value->SetPreferSyntheticValue(false); + + PythonObject val_arg = SWIGBridge::ToSWIGWrapper(std::move(sb_value)); + if (!val_arg.IsAllocated()) + return PythonObject(); + + PythonObject result = pfunc(val_arg, dict); + + if (result.IsAllocated()) + return result; + + return PythonObject(); +} + +PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject( + const char *python_class_name, const char *session_dictionary_name, + lldb::DebuggerSP debugger_sp) { + if (python_class_name == NULL || python_class_name[0] == '\0' || + !session_dictionary_name) + return PythonObject(); + + PyErr_Cleaner py_err_cleaner(true); + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_class_name, dict); + + if (!pfunc.IsAllocated()) + return PythonObject(); + + return pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger_sp)), dict); +} + +PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedBreakpointResolver( + const char *python_class_name, const char *session_dictionary_name, + const StructuredDataImpl &args_impl, + const lldb::BreakpointSP &breakpoint_sp) { + + if (python_class_name == NULL || python_class_name[0] == '\0' || + !session_dictionary_name) + return PythonObject(); + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_class_name, dict); + + if (!pfunc.IsAllocated()) + return PythonObject(); + + PythonObject result = + pfunc(SWIGBridge::ToSWIGWrapper(breakpoint_sp), SWIGBridge::ToSWIGWrapper(args_impl), dict); + // FIXME: At this point we should check that the class we found supports all + // the methods that we need. + + if (result.IsAllocated()) { + // Check that __callback__ is defined: + auto callback_func = result.ResolveName<PythonCallable>("__callback__"); + if (callback_func.IsAllocated()) + return result; + } + return PythonObject(); +} + +unsigned int lldb_private::python::SWIGBridge::LLDBSwigPythonCallBreakpointResolver( + void *implementor, const char *method_name, + lldb_private::SymbolContext *sym_ctx) { + PyErr_Cleaner py_err_cleaner(false); + PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor)); + auto pfunc = self.ResolveName<PythonCallable>(method_name); + + if (!pfunc.IsAllocated()) + return 0; + + PythonObject result = sym_ctx ? pfunc(SWIGBridge::ToSWIGWrapper(*sym_ctx)) : pfunc(); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return 0; + } + + // The callback will return a bool, but we're need to also return ints + // so we're squirrelling the bool through as an int... And if you return + // nothing, we'll continue. + if (strcmp(method_name, "__callback__") == 0) { + if (result.get() == Py_False) + return 0; + else + return 1; + } + + long long ret_val = unwrapOrSetPythonException(As<long long>(result)); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return 0; + } + + return ret_val; +} + +PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedStopHook( + lldb::TargetSP target_sp, const char *python_class_name, + const char *session_dictionary_name, const StructuredDataImpl &args_impl, + Status &error) { + if (python_class_name == NULL || python_class_name[0] == '\0') { + error.SetErrorString("Empty class name."); + return PythonObject(); + } + if (!session_dictionary_name) { + error.SetErrorString("No session dictionary"); + return PythonObject(); + } + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error.SetErrorStringWithFormat("Could not find class: %s.", + python_class_name); + return PythonObject(); + } + + PythonObject result = + pfunc(SWIGBridge::ToSWIGWrapper(target_sp), SWIGBridge::ToSWIGWrapper(args_impl), dict); + + if (result.IsAllocated()) { + // Check that the handle_stop callback is defined: + auto callback_func = result.ResolveName<PythonCallable>("handle_stop"); + if (callback_func.IsAllocated()) { + if (auto args_info = callback_func.GetArgInfo()) { + size_t num_args = (*args_info).max_positional_args; + if (num_args != 2) { + error.SetErrorStringWithFormat( + "Wrong number of args for " + "handle_stop callback, should be 2 (excluding self), got: %zu", + num_args); + return PythonObject(); + } else + return result; + } else { + error.SetErrorString("Couldn't get num arguments for handle_stop " + "callback."); + return PythonObject(); + } + return result; + } else { + error.SetErrorStringWithFormat("Class \"%s\" is missing the required " + "handle_stop callback.", + python_class_name); + } + } + return PythonObject(); +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonStopHookCallHandleStop( + void *implementor, lldb::ExecutionContextRefSP exc_ctx_sp, + lldb::StreamSP stream) { + // handle_stop will return a bool with the meaning "should_stop"... + // If you return nothing we'll assume we are going to stop. + // Also any errors should return true, since we should stop on error. + + PyErr_Cleaner py_err_cleaner(false); + PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor)); + auto pfunc = self.ResolveName<PythonCallable>("handle_stop"); + + if (!pfunc.IsAllocated()) + return true; + + std::shared_ptr<lldb::SBStream> sb_stream = std::make_shared<lldb::SBStream>(); + PythonObject sb_stream_arg = SWIGBridge::ToSWIGWrapper(sb_stream); + PythonObject result = + pfunc(SWIGBridge::ToSWIGWrapper(std::move(exc_ctx_sp)), sb_stream_arg); + + if (PyErr_Occurred()) { + stream->PutCString("Python error occurred handling stop-hook."); + PyErr_Print(); + PyErr_Clear(); + return true; + } + + // Now add the result to the output stream. SBStream only + // makes an internally help StreamString which I can't interpose, so I + // have to copy it over here. + stream->PutCString(sb_stream->GetData()); + sb_stream_arg.release(); + + if (result.get() == Py_False) + return false; + else + return true; +} + +// wrapper that calls an optional instance member of an object taking no +// arguments +static PyObject *LLDBSwigPython_CallOptionalMember( + PyObject * implementor, char *callee_name, + PyObject *ret_if_not_found = Py_None, bool *was_found = NULL) { + PyErr_Cleaner py_err_cleaner(false); + + PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor)); + auto pfunc = self.ResolveName<PythonCallable>(callee_name); + + if (!pfunc.IsAllocated()) { + if (was_found) + *was_found = false; + Py_XINCREF(ret_if_not_found); + return ret_if_not_found; + } + + if (was_found) + *was_found = true; + + PythonObject result = pfunc(); + return result.release(); +} + +size_t lldb_private::python::SWIGBridge::LLDBSwigPython_CalculateNumChildren(PyObject * implementor, + uint32_t max) { + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("num_children"); + + if (!pfunc.IsAllocated()) + return 0; + + auto arg_info = pfunc.GetArgInfo(); + if (!arg_info) { + llvm::consumeError(arg_info.takeError()); + return 0; + } + + size_t ret_val; + if (arg_info.get().max_positional_args < 1) + ret_val = unwrapOrSetPythonException(As<long long>(pfunc.Call())); + else + ret_val = unwrapOrSetPythonException( + As<long long>(pfunc.Call(PythonInteger(max)))); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return 0; + } + + if (arg_info.get().max_positional_args < 1) + ret_val = std::min(ret_val, static_cast<size_t>(max)); + + return ret_val; +} + +PyObject *lldb_private::python::SWIGBridge::LLDBSwigPython_GetChildAtIndex(PyObject * implementor, + uint32_t idx) { + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("get_child_at_index"); + + if (!pfunc.IsAllocated()) + return nullptr; + + PythonObject result = pfunc(PythonInteger(idx)); + + if (!result.IsAllocated()) + return nullptr; + + lldb::SBValue *sbvalue_ptr = nullptr; + if (SWIG_ConvertPtr(result.get(), (void **)&sbvalue_ptr, + SWIGTYPE_p_lldb__SBValue, 0) == -1) + return nullptr; + + if (sbvalue_ptr == nullptr) + return nullptr; + + return result.release(); +} + +int lldb_private::python::SWIGBridge::LLDBSwigPython_GetIndexOfChildWithName( + PyObject * implementor, const char *child_name) { + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("get_child_index"); + + if (!pfunc.IsAllocated()) + return UINT32_MAX; + + llvm::Expected<PythonObject> result = pfunc.Call(PythonString(child_name)); + + long long retval = + unwrapOrSetPythonException(As<long long>(std::move(result))); + + if (PyErr_Occurred()) { + PyErr_Clear(); // FIXME print this? do something else + return UINT32_MAX; + } + + if (retval >= 0) + return (uint32_t)retval; + + return UINT32_MAX; +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPython_UpdateSynthProviderInstance(PyObject * + implementor) { + bool ret_val = false; + + static char callee_name[] = "update"; + + PyObject *py_return = + LLDBSwigPython_CallOptionalMember(implementor, callee_name); + + if (py_return == Py_True) + ret_val = true; + + Py_XDECREF(py_return); + + return ret_val; +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPython_MightHaveChildrenSynthProviderInstance( + PyObject * implementor) { + bool ret_val = false; + + static char callee_name[] = "has_children"; + + PyObject *py_return = + LLDBSwigPython_CallOptionalMember(implementor, callee_name, Py_True); + + if (py_return == Py_True) + ret_val = true; + + Py_XDECREF(py_return); + + return ret_val; +} + +PyObject *lldb_private::python::SWIGBridge::LLDBSwigPython_GetValueSynthProviderInstance( + PyObject * implementor) { + PyObject *ret_val = nullptr; + + static char callee_name[] = "get_value"; + + PyObject *py_return = + LLDBSwigPython_CallOptionalMember(implementor, callee_name, Py_None); + + if (py_return == Py_None || py_return == nullptr) + ret_val = nullptr; + + lldb::SBValue *sbvalue_ptr = NULL; + + if (SWIG_ConvertPtr(py_return, (void **)&sbvalue_ptr, + SWIGTYPE_p_lldb__SBValue, 0) == -1) + ret_val = nullptr; + else if (sbvalue_ptr == NULL) + ret_val = nullptr; + else + ret_val = py_return; + + Py_XDECREF(py_return); + return ret_val; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBData(PyObject * data) { + lldb::SBData *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBData, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject * data) { + lldb::SBBreakpoint *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBBreakpoint, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject * data) { + lldb::SBAttachInfo *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBAttachInfo, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject * data) { + lldb::SBLaunchInfo *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBLaunchInfo, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBError(PyObject * data) { + lldb::SBError *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBError, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBEvent(PyObject * data) { + lldb::SBEvent *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBEvent, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBStream(PyObject * data) { + lldb::SBStream *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBStream, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBValue(PyObject * data) { + lldb::SBValue *sb_ptr = NULL; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBValue, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject * + data) { + lldb::SBMemoryRegionInfo *sb_ptr = NULL; + + int valid_cast = SWIG_ConvertPtr(data, (void **)&sb_ptr, + SWIGTYPE_p_lldb__SBMemoryRegionInfo, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommand( + const char *python_function_name, const char *session_dictionary_name, + lldb::DebuggerSP debugger, const char *args, + lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp) { + + PyErr_Cleaner py_err_cleaner(true); + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return false; + + auto argc = pfunc.GetArgInfo(); + if (!argc) { + llvm::consumeError(argc.takeError()); + return false; + } + PythonObject debugger_arg = SWIGBridge::ToSWIGWrapper(std::move(debugger)); + auto cmd_retobj_arg = SWIGBridge::ToSWIGWrapper(cmd_retobj); + + if (argc.get().max_positional_args < 5u) + pfunc(debugger_arg, PythonString(args), cmd_retobj_arg.obj(), dict); + else + pfunc(debugger_arg, PythonString(args), + SWIGBridge::ToSWIGWrapper(std::move(exe_ctx_ref_sp)), cmd_retobj_arg.obj(), dict); + + return true; +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommandObject( + PyObject *implementor, lldb::DebuggerSP debugger, const char *args, + lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp) { + + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("__call__"); + + if (!pfunc.IsAllocated()) + return false; + + auto cmd_retobj_arg = SWIGBridge::ToSWIGWrapper(cmd_retobj); + + pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), PythonString(args), + SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp), cmd_retobj_arg.obj()); + + return true; +} + +std::optional<std::string> +lldb_private::python::SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor, + std::string &command) { + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("get_repeat_command"); + // If not implemented, repeat the exact command. + if (!pfunc.IsAllocated()) + return std::nullopt; + + PythonString command_str(command); + PythonObject result = pfunc(command_str); + + // A return of None is the equivalent of nullopt - means repeat + // the command as is: + if (result.IsNone()) + return std::nullopt; + + return result.Str().GetString().str(); +} + +#include "lldb/Interpreter/CommandReturnObject.h" + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject( + PyObject *implementor, lldb::DebuggerSP debugger, lldb_private::StructuredDataImpl &args_impl, + lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp) { + + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("__call__"); + + if (!pfunc.IsAllocated()) { + cmd_retobj.AppendError("Could not find '__call__' method in implementation class"); + return false; + } + + pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), SWIGBridge::ToSWIGWrapper(args_impl), + SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp), SWIGBridge::ToSWIGWrapper(cmd_retobj).obj()); + + return true; +} + +PythonObject lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin( + const char *python_class_name, const char *session_dictionary_name, + const lldb::ProcessSP &process_sp) { + if (python_class_name == NULL || python_class_name[0] == '\0' || + !session_dictionary_name) + return PythonObject(); + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_class_name, dict); + + if (!pfunc.IsAllocated()) + return PythonObject(); + + return pfunc(SWIGBridge::ToSWIGWrapper(process_sp)); +} + +PythonObject lldb_private::python::SWIGBridge::LLDBSWIGPython_CreateFrameRecognizer( + const char *python_class_name, const char *session_dictionary_name) { + if (python_class_name == NULL || python_class_name[0] == '\0' || + !session_dictionary_name) + return PythonObject(); + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_class_name, dict); + + if (!pfunc.IsAllocated()) + return PythonObject(); + + return pfunc(); +} + +PyObject *lldb_private::python::SWIGBridge::LLDBSwigPython_GetRecognizedArguments( + PyObject * implementor, const lldb::StackFrameSP &frame_sp) { + static char callee_name[] = "get_recognized_arguments"; + + PythonObject arg = SWIGBridge::ToSWIGWrapper(frame_sp); + + PythonString str(callee_name); + PyObject *result = + PyObject_CallMethodObjArgs(implementor, str.get(), arg.get(), NULL); + return result; +} + +void *lldb_private::python::SWIGBridge::LLDBSWIGPython_GetDynamicSetting( + void *module, const char *setting, const lldb::TargetSP &target_sp) { + if (!module || !setting) + Py_RETURN_NONE; + + PyErr_Cleaner py_err_cleaner(true); + PythonObject py_module(PyRefType::Borrowed, (PyObject *)module); + auto pfunc = py_module.ResolveName<PythonCallable>("get_dynamic_setting"); + + if (!pfunc.IsAllocated()) + Py_RETURN_NONE; + + auto result = pfunc(SWIGBridge::ToSWIGWrapper(target_sp), PythonString(setting)); + + return result.release(); +} + +bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordProcess( + const char *python_function_name, const char *session_dictionary_name, + const lldb::ProcessSP &process, std::string &output) { + + if (python_function_name == NULL || python_function_name[0] == '\0' || + !session_dictionary_name) + return false; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return false; + + auto result = pfunc(SWIGBridge::ToSWIGWrapper(process), dict); + + output = result.Str().GetString().str(); + + return true; +} + +std::optional<std::string> lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordThread( + const char *python_function_name, const char *session_dictionary_name, + lldb::ThreadSP thread) { + if (python_function_name == NULL || python_function_name[0] == '\0' || + !session_dictionary_name) + return std::nullopt; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return std::nullopt; + + auto result = pfunc(SWIGBridge::ToSWIGWrapper(std::move(thread)), dict); + + return result.Str().GetString().str(); +} + +bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordTarget( + const char *python_function_name, const char *session_dictionary_name, + const lldb::TargetSP &target, std::string &output) { + + if (python_function_name == NULL || python_function_name[0] == '\0' || + !session_dictionary_name) + return false; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return false; + + auto result = pfunc(SWIGBridge::ToSWIGWrapper(target), dict); + + output = result.Str().GetString().str(); + + return true; +} + +std::optional<std::string> lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordFrame( + const char *python_function_name, const char *session_dictionary_name, + lldb::StackFrameSP frame) { + if (python_function_name == NULL || python_function_name[0] == '\0' || + !session_dictionary_name) + return std::nullopt; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return std::nullopt; + + auto result = pfunc(SWIGBridge::ToSWIGWrapper(std::move(frame)), dict); + + return result.Str().GetString().str(); +} + +bool lldb_private::python::SWIGBridge::LLDBSWIGPythonRunScriptKeywordValue( + const char *python_function_name, const char *session_dictionary_name, + const lldb::ValueObjectSP &value, std::string &output) { + + if (python_function_name == NULL || python_function_name[0] == '\0' || + !session_dictionary_name) + return false; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + if (!pfunc.IsAllocated()) + return false; + + auto result = pfunc(SWIGBridge::ToSWIGWrapper(value), dict); + + output = result.Str().GetString().str(); + + return true; +} + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallModuleInit( + const char *python_module_name, const char *session_dictionary_name, + lldb::DebuggerSP debugger) { + std::string python_function_name_string = python_module_name; + python_function_name_string += ".__lldb_init_module"; + const char *python_function_name = python_function_name_string.c_str(); + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( + session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + python_function_name, dict); + + // This method is optional and need not exist. So if we don't find it, + // it's actually a success, not a failure. + if (!pfunc.IsAllocated()) + return true; + + pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), dict); + + return true; +} + +lldb::ValueObjectSP lldb_private::python::SWIGBridge::LLDBSWIGPython_GetValueObjectSPFromSBValue( + void *data) { + lldb::ValueObjectSP valobj_sp; + if (data) { + lldb::SBValue *sb_ptr = (lldb::SBValue *)data; + valobj_sp = sb_ptr->GetSP(); + } + return valobj_sp; +} + +// For the LogOutputCallback functions +static void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, + void *baton) { + if (baton != Py_None) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyObject *result = PyObject_CallFunction( + reinterpret_cast<PyObject *>(baton), const_cast<char *>("s"), str); + Py_XDECREF(result); + SWIG_PYTHON_THREAD_END_BLOCK; + } +} + +// For DebuggerTerminateCallback functions +static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t debugger_id, + void *baton) { + if (baton != Py_None) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + PyObject *result = PyObject_CallFunction( + reinterpret_cast<PyObject *>(baton), const_cast<char *>("l"), debugger_id); + Py_XDECREF(result); + SWIG_PYTHON_THREAD_END_BLOCK; + } +} + +static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) { + bool ret_val = false; + if (baton != Py_None) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + // Create a PyList of items since we're going to pass it to the callback as a tuple + // of arguments. + PyObject *py_argv = PyList_New(0); + for (const char **arg = argv; arg && *arg; arg++) { + std::string arg_string = *arg; + PyObject *py_string = PyUnicode_FromStringAndSize(arg_string.c_str(), arg_string.size()); + PyList_Append(py_argv, py_string); + } + + PyObject *result = PyObject_CallObject( + reinterpret_cast<PyObject *>(baton), PyList_AsTuple(py_argv)); + ret_val = result ? PyObject_IsTrue(result) : false; + Py_XDECREF(result); + SWIG_PYTHON_THREAD_END_BLOCK; + } + return ret_val; +} + +static SBError LLDBSwigPythonCallLocateModuleCallback( + void *callback_baton, const SBModuleSpec &module_spec_sb, + SBFileSpec &module_file_spec_sb, SBFileSpec &symbol_file_spec_sb) { + SWIG_Python_Thread_Block swig_thread_block; + + PyErr_Cleaner py_err_cleaner(true); + PythonObject module_spec_arg = SWIGBridge::ToSWIGWrapper( + std::make_unique<SBModuleSpec>(module_spec_sb)); + PythonObject module_file_spec_arg = SWIGBridge::ToSWIGWrapper( + std::make_unique<SBFileSpec>(module_file_spec_sb)); + PythonObject symbol_file_spec_arg = SWIGBridge::ToSWIGWrapper( + std::make_unique<SBFileSpec>(symbol_file_spec_sb)); + + PythonCallable callable = + Retain<PythonCallable>(reinterpret_cast<PyObject *>(callback_baton)); + if (!callable.IsValid()) { + return SBError("The callback callable is not valid."); + } + + PythonObject result = callable(module_spec_arg, module_file_spec_arg, + symbol_file_spec_arg); + + if (!result.IsAllocated()) + return SBError("No result."); + lldb::SBError *sb_error_ptr = nullptr; + if (SWIG_ConvertPtr(result.get(), (void **)&sb_error_ptr, + SWIGTYPE_p_lldb__SBError, 0) == -1) { + return SBError("Result is not SBError."); + } + + if (sb_error_ptr->Success()) { + lldb::SBFileSpec *sb_module_file_spec_ptr = nullptr; + if (SWIG_ConvertPtr(module_file_spec_arg.get(), + (void **)&sb_module_file_spec_ptr, + SWIGTYPE_p_lldb__SBFileSpec, 0) == -1) + return SBError("module_file_spec is not SBFileSpec."); + + lldb::SBFileSpec *sb_symbol_file_spec_ptr = nullptr; + if (SWIG_ConvertPtr(symbol_file_spec_arg.get(), + (void **)&sb_symbol_file_spec_ptr, + SWIGTYPE_p_lldb__SBFileSpec, 0) == -1) + return SBError("symbol_file_spec is not SBFileSpec."); + + module_file_spec_sb = *sb_module_file_spec_ptr; + symbol_file_spec_sb = *sb_symbol_file_spec_ptr; + } + + return *sb_error_ptr; +} +%} diff --git a/contrib/llvm-project/lldb/bindings/python/python.swig b/contrib/llvm-project/lldb/bindings/python/python.swig new file mode 100644 index 000000000000..278c0eed2bab --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/python/python.swig @@ -0,0 +1,137 @@ +/* + lldb.swig + + This is the input file for SWIG, to create the appropriate C++ wrappers and + functions for various scripting languages, to enable them to call the + liblldb Script Bridge functions. +*/ + +/* Define our module docstring. */ +%define DOCSTRING +"The lldb module contains the public APIs for Python binding. + +Some of the important classes are described here: + +* :py:class:`SBTarget`: Represents the target program running under the debugger. +* :py:class:`SBProcess`: Represents the process associated with the target program. +* :py:class:`SBThread`: Represents a thread of execution. :py:class:`SBProcess` contains SBThreads. +* :py:class:`SBFrame`: Represents one of the stack frames associated with a thread. :py:class:`SBThread` + contains SBFrame(s). +* :py:class:`SBSymbolContext`: A container that stores various debugger related info. +* :py:class:`SBValue`: Represents the value of a variable, a register, or an expression. +* :py:class:`SBModule`: Represents an executable image and its associated object and symbol + files. :py:class:`SBTarget` contains SBModule. +* :py:class:`SBBreakpoint`: Represents a logical breakpoint and its associated settings. + :py:class:`SBTarget` contains SBBreakpoints. +* :py:class:`SBSymbol`: Represents the symbol possibly associated with a stack frame. +* :py:class:`SBCompileUnit`: Represents a compilation unit, or compiled source file. +* :py:class:`SBFunction`: Represents a generic function, which can be inlined or not. +* :py:class:`SBBlock`: Represents a lexical block. :py:class:`SBFunction` contains SBBlocks. +* :py:class:`SBLineEntry`: Specifies an association with a contiguous range of instructions + and a source file location. :py:class:`SBCompileUnit` contains SBLineEntry. + +The different enums in the `lldb` module are described in :doc:`python_api_enums`. + +" +%enddef + +/* +Since version 3.0.9, swig's logic for importing the native module has changed in +a way that is incompatible with our usage of the python module as __init__.py +(See swig bug #769). Fortunately, since version 3.0.11, swig provides a way for +us to override the module import logic to suit our needs. This does that. + +Older swig versions will simply ignore this setting. +*/ +%define MODULEIMPORT +"try: + # Try an absolute import first. If we're being loaded from lldb, + # _lldb should be a built-in module. + import $module +except ImportError: + # Relative import should work if we are being loaded by Python. + from . import $module" +%enddef + +// The name of the module to be created. +%module(docstring=DOCSTRING, moduleimport=MODULEIMPORT) lldb + +// Parameter types will be used in the autodoc string. +%feature("autodoc", "1"); + +%define ARRAYHELPER(type,name) +%inline %{ +type *new_ ## name (int nitems) { + return (type *) malloc(sizeof(type)*nitems); +} +void delete_ ## name(type *t) { + free(t); +} +type name ## _get(type *t, int index) { + return t[index]; +} +void name ## _set(type *t, int index, type val) { + t[index] = val; +} +%} +%enddef + +%pythoncode%{ +import uuid +import re +import os +%} + +// Include the version of swig that was used to generate this interface. +%define EMBED_VERSION(VERSION) +%pythoncode%{ +# SWIG_VERSION is written as a single hex number, but the components of it are +# meant to be interpreted in decimal. So, 0x030012 is swig 3.0.12, and not +# 3.0.18. +def _to_int(hex): + return hex // 0x10 % 0x10 * 10 + hex % 0x10 +swig_version = (_to_int(VERSION // 0x10000), _to_int(VERSION // 0x100), _to_int(VERSION)) +del _to_int +%} +%enddef +EMBED_VERSION(SWIG_VERSION) + +%pythoncode%{ +# =================================== +# Iterator for lldb container objects +# =================================== +def lldb_iter(obj, getsize, getelem): + """A generator adaptor to support iteration for lldb container objects.""" + size = getattr(obj, getsize) + elem = getattr(obj, getelem) + for i in range(size()): + yield elem(i) +%} + +%include <std_string.i> +%include "python-typemaps.swig" +%include "macros.swig" +%include "headers.swig" + +%{ +#include "../source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h" +#include "../source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h" +#include "../bindings/python/python-swigsafecast.swig" +using namespace lldb_private; +using namespace lldb_private::python; +using namespace lldb; +%} + +%include "interfaces.swig" +%include "python-extensions.swig" +%include "python-wrapper.swig" + +%pythoncode%{ +debugger_unique_id = 0 +SBDebugger.Initialize() +debugger = None +target = None +process = None +thread = None +frame = None +%} |