[lldb/SWIG] Refactor extensions to be non Python-specific (2/2)
authorJonas Devlieghere <jonas@devlieghere.com>
Thu, 9 Jan 2020 00:13:03 +0000 (16:13 -0800)
committerJonas Devlieghere <jonas@devlieghere.com>
Thu, 9 Jan 2020 00:34:09 +0000 (16:34 -0800)
The current SWIG extensions for the string conversion operator is Python
specific because it uses the PythonObjects. This means that the code
cannot be reused for other SWIG supported languages such as Lua.

This reimplements the extensions in a more generic way that can be
reused. It uses a SWIG macro to reduce code duplication.

Differential revision: https://reviews.llvm.org/D72377

25 files changed:
lldb/scripts/Python/python-extensions.swig
lldb/scripts/interface/SBAddress.i
lldb/scripts/interface/SBBlock.i
lldb/scripts/interface/SBBreakpoint.i
lldb/scripts/interface/SBBreakpointLocation.i
lldb/scripts/interface/SBBreakpointName.i
lldb/scripts/interface/SBCommandReturnObject.i
lldb/scripts/interface/SBCompileUnit.i
lldb/scripts/interface/SBData.i
lldb/scripts/interface/SBDebugger.i
lldb/scripts/interface/SBDeclaration.i
lldb/scripts/interface/SBError.i
lldb/scripts/interface/SBFileSpec.i
lldb/scripts/interface/SBFrame.i
lldb/scripts/interface/SBFunction.i
lldb/scripts/interface/SBInstruction.i
lldb/scripts/interface/SBInstructionList.i
lldb/scripts/interface/SBLineEntry.i
lldb/scripts/interface/SBMemoryRegionInfo.i
lldb/scripts/interface/SBModule.i
lldb/scripts/interface/SBModuleSpec.i
lldb/scripts/interface/SBTarget.i
lldb/scripts/lldb.swig
lldb/scripts/lldb_lua.swig
lldb/scripts/macros.swig [new file with mode: 0644]

index dbd4b1d..36dac19 100644 (file)
@@ -1,42 +1,4 @@
-%extend lldb::SBAddress {
-        %nothreadallow;
-        PyObject *lldb::SBAddress::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-%extend lldb::SBBlock {
-        %nothreadallow;
-        PyObject *lldb::SBBlock::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
 %extend lldb::SBBreakpoint {
-        %nothreadallow;
-        PyObject *lldb::SBBreakpoint::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-
     %pythoncode %{
         def __eq__(self, rhs):
             if not isinstance(rhs, type(self)):
 
             return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs)
     %}
-
-}
-%extend lldb::SBBreakpointLocation {
-        %nothreadallow;
-        PyObject *lldb::SBBreakpointLocation::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description, lldb::eDescriptionLevelFull);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-
-%extend lldb::SBBreakpointName {
-        %nothreadallow;
-        PyObject *lldb::SBBreakpointName::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
 }
 
 %extend lldb::SBBroadcaster {
 }
 
 %extend lldb::SBCommandReturnObject {
-        %nothreadallow;
-        PyObject *lldb::SBCommandReturnObject::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-
         /* 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"
         void lldb::SBCommandReturnObject::flush ()
         {}
 }
+
 %extend lldb::SBCompileUnit {
-        %nothreadallow;
-        PyObject *lldb::SBCompileUnit::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
     %pythoncode %{
         def __eq__(self, rhs):
             if not isinstance(rhs, type(self)):
             return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs)
     %}
 }
-%extend lldb::SBData {
-        %nothreadallow;
-        PyObject *lldb::SBData::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-%extend lldb::SBDebugger {
-        %nothreadallow;
-        PyObject *lldb::SBDebugger::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-%extend lldb::SBDeclaration {
-        %nothreadallow;
-        PyObject *lldb::SBDeclaration::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
 
+%extend lldb::SBDeclaration {
     %pythoncode %{
         def __eq__(self, rhs):
             if not isinstance(rhs, type(self)):
 
             return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs)
     %}
-
-}
-%extend lldb::SBError {
-        %nothreadallow;
-        PyObject *lldb::SBError::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-%extend lldb::SBFileSpec {
-        %nothreadallow;
-        PyObject *lldb::SBFileSpec::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
 }
-%extend lldb::SBFrame {
-        %nothreadallow;
-        PyObject *lldb::SBFrame::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-%extend lldb::SBFunction {
-        %nothreadallow;
-        PyObject *lldb::SBFunction::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
 
+%extend lldb::SBFunction {
     %pythoncode %{
         def __eq__(self, rhs):
             if not isinstance(rhs, type(self)):
 
             return getattr(_lldb,self.__class__.__name__+"___ne__")(self, rhs)
     %}
-
-}
-%extend lldb::SBInstruction {
-        %nothreadallow;
-        PyObject *lldb::SBInstruction::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-%extend lldb::SBInstructionList {
-        %nothreadallow;
-        PyObject *lldb::SBInstructionList::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
 }
-%extend lldb::SBLineEntry {
-        %nothreadallow;
-        PyObject *lldb::SBLineEntry::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
 
+%extend lldb::SBLineEntry {
     %pythoncode %{
         def __eq__(self, rhs):
             if not isinstance(rhs, type(self)):
     %}
 }
 
-%extend lldb::SBMemoryRegionInfo {
-        %nothreadallow;
-        PyObject *lldb::SBMemoryRegionInfo::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-
 %extend lldb::SBModule {
-        %nothreadallow;
-        PyObject *lldb::SBModule::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-
     %pythoncode %{
         def __eq__(self, rhs):
             if not isinstance(rhs, type(self)):
     %}
 }
 
-%extend lldb::SBModuleSpec {
-        %nothreadallow;
-        PyObject *lldb::SBModuleSpec::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-
-%extend lldb::SBModuleSpecList {
-        %nothreadallow;
-        PyObject *lldb::SBModuleSpecList::__str__ (){
-                lldb::SBStream description;
-                $self->GetDescription (description);
-                const char *desc = description.GetData();
-                size_t desc_len = description.GetSize();
-                if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-                    --desc_len;
-                return PythonString(llvm::StringRef(desc, desc_len)).release();
-        }
-        %clearnothreadallow;
-}
-
 %extend lldb::SBProcess {
         %nothreadallow;
         PyObject *lldb::SBProcess::__str__ (){
index 6c5352b..4658534 100644 (file)
@@ -140,6 +140,8 @@ public:
     lldb::SBLineEntry
     GetLineEntry ();
 
+    STRING_EXTENSION(SBAddress)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def __get_load_addr_property__ (self):
index 73079a1..8bd8e37 100644 (file)
@@ -100,6 +100,8 @@ public:
                    bool locals,
                    bool statics);
 
+    STRING_EXTENSION(SBBlock)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def get_range_at_index(self, idx):
index f84f2ad..2035434 100644 (file)
@@ -249,6 +249,8 @@ public:
     bool
     IsHardware ();
 
+    STRING_EXTENSION(SBBreakpoint)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
 
index 44fd42b..dc39c83 100644 (file)
@@ -134,6 +134,8 @@ public:
 
     SBBreakpoint
     GetBreakpoint ();
+
+    STRING_EXTENSION_LEVEL(SBBreakpointLocation, lldb::eDescriptionLevelFull)
 };
 
 } // namespace lldb
index 2a06d0a..e280d42 100644 (file)
@@ -108,6 +108,7 @@ public:
 
   bool GetDescription(lldb::SBStream &description);
 
+  STRING_EXTENSION(SBBreakpointName)
 };
 
 } // namespace lldb
index 73d4001..affa165 100644 (file)
@@ -96,6 +96,8 @@ public:
     void SetImmediateOutputFile(lldb::FileSP BORROWED);
     void SetImmediateErrorFile(lldb::FileSP BORROWED);
 
+    STRING_EXTENSION(SBCommandReturnObject)
+
     %extend {
         // transfer_ownership does nothing, and is here for compatibility with
         // old scripts.  Ownership is tracked by reference count in the ordinary way.
index bc2d45a..d6a4c07 100644 (file)
@@ -116,6 +116,8 @@ public:
     bool
     operator != (const lldb::SBCompileUnit &rhs) const;
 
+    STRING_EXTENSION(SBCompileUnit)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def __iter__(self):
index fdaa696..3e74240 100644 (file)
@@ -134,6 +134,8 @@ public:
     bool
     SetDataFromDoubleArray (double* array, size_t array_len);
 
+    STRING_EXTENSION(SBData)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
 
index 52f6584..f2e23a7 100644 (file)
@@ -479,6 +479,8 @@ public:
     lldb::SBTypeSynthetic
     GetSyntheticForType (lldb::SBTypeNameSpecifier);
 
+    STRING_EXTENSION(SBDebugger)
+
     %feature("docstring",
 "Launch a command interpreter session. Commands are read from standard input or
 from the input handle specified for the debugger object. Output/errors are
index cdaec85..621c1a0 100644 (file)
@@ -53,6 +53,8 @@ namespace lldb {
         bool
         operator != (const lldb::SBDeclaration &rhs) const;
 
+        STRING_EXTENSION(SBDeclaration)
+
 #ifdef SWIGPYTHON
         %pythoncode %{
             file = property(GetFileSpec, None, doc='''A read only property that returns an lldb object that represents the file (lldb.SBFileSpec) for this line entry.''')
index 96cd6c4..ea48e22 100644 (file)
@@ -105,6 +105,8 @@ public:
     bool
     GetDescription (lldb::SBStream &description);
 
+    STRING_EXTENSION(SBError)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         value = property(GetError, None, doc='''A read only property that returns the same result as GetError().''')
index 07a7630..d287a94 100644 (file)
@@ -80,6 +80,8 @@ public:
     void
     AppendPathComponent (const char *file_or_directory);
 
+    STRING_EXTENSION(SBFileSpec)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def __get_fullpath__(self):
index 811f7f2..c65b88f 100644 (file)
@@ -285,6 +285,8 @@ public:
     bool
     GetDescription (lldb::SBStream &description);
 
+    STRING_EXTENSION(SBFrame)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def get_all_variables(self):
index 7b157bb..630c4db 100644 (file)
@@ -111,6 +111,8 @@ public:
     bool
     operator != (const lldb::SBFunction &rhs) const;
 
+    STRING_EXTENSION(SBFunction)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def get_instructions_from_current_target (self):
index 0968821..d50a080 100644 (file)
@@ -74,6 +74,8 @@ public:
     bool
     TestEmulation (lldb::SBStream &output_stream, const char *test_file);
 
+    STRING_EXTENSION(SBInstruction)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def __mnemonic_property__ (self):
index d50deba..1357323 100644 (file)
@@ -66,6 +66,8 @@ public:
     bool
     DumpEmulationForAllInstructions (const char *triple);
 
+    STRING_EXTENSION(SBInstructionList)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def __iter__(self):
index 90f60df..be36537 100644 (file)
@@ -84,6 +84,8 @@ public:
     bool
     operator != (const lldb::SBLineEntry &rhs) const;
 
+    STRING_EXTENSION(SBLineEntry)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         file = property(GetFileSpec, None, doc='''A read only property that returns an lldb object that represents the file (lldb.SBFileSpec) for this line entry.''')
index 7a59d00..6a2ad6a 100644 (file)
@@ -55,6 +55,7 @@ public:
     bool
     GetDescription (lldb::SBStream &description);
 
+    STRING_EXTENSION(SBMemoryRegionInfo)
 };
 
 } // namespace lldb
index 03c8aeb..a9d9480 100644 (file)
@@ -344,6 +344,8 @@ public:
     lldb::SBAddress
     GetObjectFileEntryPointAddress() const;
 
+    STRING_EXTENSION(SBModule)
+
 #ifdef SWIGPYTHON
     %pythoncode %{
         def __len__(self):
index ec4e9bb..64d0aa6 100644 (file)
@@ -91,6 +91,7 @@ public:
     bool
     GetDescription (lldb::SBStream &description);
 
+    STRING_EXTENSION(SBModuleSpec)
 };
 
 
@@ -127,6 +128,7 @@ public:
     bool
     GetDescription (lldb::SBStream &description);
 
+    STRING_EXTENSION(SBModuleSpecList)
 };
 
 } // namespace lldb
index 02c70b6..371bf5c 100644 (file)
@@ -967,21 +967,7 @@ public:
     lldb::SBValue
     EvaluateExpression (const char *expr, const lldb::SBExpressionOptions &options);
 
-  %extend {
-    %nothreadallow;
-    std::string lldb::SBTarget::__str__(){
-      lldb::SBStream stream;
-      $self->GetDescription (stream, lldb::eDescriptionLevelBrief);
-
-      const char *desc = stream.GetData();
-      size_t desc_len = stream.GetSize();
-      if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
-        --desc_len;
-
-      return std::string(desc, desc_len);
-    }
-    %clearnothreadallow;
-  }
+    STRING_EXTENSION_LEVEL(SBTarget, lldb::eDescriptionLevelBrief)
 
 #ifdef SWIGPYTHON
     %pythoncode %{
index c3b9083..bebf9bf 100644 (file)
@@ -59,6 +59,23 @@ except ImportError:
 // 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
@@ -95,6 +112,7 @@ def lldb_iter(obj, getsize, getelem):
 
 %include <std_string.i>
 %include "./Python/python-typemaps.swig"
+%include "./macros.swig"
 %include "./headers.swig"
 
 %{
index bf88090..3b279a6 100644 (file)
@@ -9,6 +9,7 @@
 %module lldb
 
 %include <std_string.i>
+%include "./macros.swig"
 %include "./headers.swig"
 
 %{
diff --git a/lldb/scripts/macros.swig b/lldb/scripts/macros.swig
new file mode 100644 (file)
index 0000000..e0756c2
--- /dev/null
@@ -0,0 +1,33 @@
+%define STRING_EXTENSION_LEVEL(Class, Level)
+%extend {
+  %nothreadallow;
+  std::string lldb:: ## Class ## ::__str__(){
+    lldb::SBStream stream;
+    $self->GetDescription (stream, Level);
+    const char *desc = stream.GetData();
+    size_t desc_len = stream.GetSize();
+    if (desc_len > 0 && (desc[desc_len-1] == 'n' || desc[desc_len-1] == 'r')) {
+      --desc_len;
+    }
+    return std::string(desc, desc_len);
+  }
+  %clearnothreadallow;
+}
+%enddef
+
+%define STRING_EXTENSION(Class)
+%extend {
+  %nothreadallow;
+  std::string lldb:: ## Class ## ::__str__(){
+    lldb::SBStream stream;
+    $self->GetDescription (stream);
+    const char *desc = stream.GetData();
+    size_t desc_len = stream.GetSize();
+    if (desc_len > 0 && (desc[desc_len-1] == 'n' || desc[desc_len-1] == 'r')) {
+      --desc_len;
+    }
+    return std::string(desc, desc_len);
+  }
+  %clearnothreadallow;
+}
+%enddef