emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master e1d93302c2: Improve support for debugging Emacs with LLDB


From: Gerd Moellmann
Subject: master e1d93302c2: Improve support for debugging Emacs with LLDB
Date: Thu, 14 Jul 2022 05:24:06 -0400 (EDT)

branch: master
commit e1d93302c29916e738552484b9363c5b9e77c5c1
Author: Gerd Möllmann <gerd@gnu.org>
Commit: Gerd Möllmann <gerd@gnu.org>

    Improve support for debugging Emacs with LLDB
    
    * etc/emacs_lldb.py: Refactor and support more Lisp types.
---
 etc/emacs_lldb.py | 217 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 141 insertions(+), 76 deletions(-)

diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py
index 4e0b20c8a5..740cbc0956 100644
--- a/etc/emacs_lldb.py
+++ b/etc/emacs_lldb.py
@@ -30,63 +30,136 @@ import lldb
 #                              Utilties
 ########################################################################
 
-# Return the Lisp_Type of Lisp_Object OBJ.
-def get_lisp_type(obj):
-    int_value = obj.GetValueAsUnsigned()
-    return obj.GetFrame().EvaluateExpression(
-        f"(enum Lisp_Type) ((EMACS_INT) {int_value} "
-        "& (1 << GCTYPEBITS) - 1)")
-
-# Return the Lisp_Type or pseudo-vector type of OBJ.
-def get_lisp_type_or_vectorlike(obj):
-    lisp_type = get_lisp_type(obj)
-    if enumerator_name(lisp_type) == "Lisp_Vectorlike":
-        vector = get_lisp_pointer(obj, "struct Lisp_Vector")
-        header_size = vector.GetValueForExpressionPath(
-            "->header.size").GetValueAsUnsigned()
-        frame = obj.GetFrame()
-        pseudo = frame.EvaluateExpression(
-            f"{header_size} & PSEUDOVECTOR_FLAG")
-        if pseudo.GetValueAsUnsigned() != 0:
-            return frame.EvaluateExpression(
-                f"(enum pvec_type) (({header_size} "
-                "& More_Lisp_Bits::PVEC_TYPE_MASK) "
-                ">> More_Lisp_Bits::PSEUDOVECTOR_AREA_BITS)")
-        return frame.EvaluateExpression("pvec_type::PVEC_NORMAL_VECTOR")
-    return lisp_type
-
-# Return Lisp_Object OBJ as pointer to TYP *.
-def get_lisp_pointer(obj, typ):
-    return obj.GetFrame().EvaluateExpression(
-        f"({typ}*) (((EMACS_INT) {obj.GetValueAsUnsigned()}) & VALMASK)")
-
-# Return Lisp_Object OBJ as pointer to Lisp_Symbol.
-def get_lisp_symbol(obj):
-    ptr = get_lisp_pointer(obj, "char")
-    offset = ptr.GetValueAsUnsigned()
-    return obj.GetFrame().EvaluateExpression(
-        f"(struct Lisp_Symbol *) ((char *) &lispsym + {offset})")
-
-# Return Lisp_Object OBJ as pointer to Lisp_String
-def get_lisp_string(obj):
-    return get_lisp_pointer(obj, "struct Lisp_String")
-
-# Return the string data of Lisp_Object OBJ which denotes a Lisp_String.
-def get_lisp_string_data(obj):
-    string = get_lisp_string(obj)
-    return string.GetValueForExpressionPath("->u.s.data")
-
-# Assuming OBJ denotes a Lisp_Symbol, return the name of the symbol.
-def get_lisp_symbol_name(obj):
-    sym = get_lisp_symbol(obj)
-    name = sym.GetValueForExpressionPath("->u.s.name")
-    return get_lisp_string_data(name)
-
-# Return a string for the enuerator ENUM.
+# Return the name of enumerator ENUM as a string.
 def enumerator_name(enum):
     enumerators = enum.GetType().GetEnumMembers()
     return enumerators[enum.GetValueAsUnsigned()].GetName()
 
+# A class wrapping an SBValue for a Lisp_Object, providing convenience
+# functions.
+class Lisp_Object:
+    # Map pvec_type enumerators to corresponding C types.
+    pvec2type = {
+        "PVEC_FRAME": "struct frame",
+        "PVEC_WINDOW": "struct window",
+        "PVEC_BIGNUM": "struct Lisp_Bignum",
+        "PVEC_MARKER": "struct Lisp_Marker",
+        "PVEC_OVERLAY": "struct Lisp_Overlay",
+        "PVEC_FINALIZER": "struct Lisp_Finalizer",
+        "PVEC_SYMBOL_WITH_POS": "struct Lisp_Symbol_With_Pos",
+        "PVEC_MISC_PTR": "",
+        "PVEC_USER_PTR": "struct Lisp_User_Ptr",
+        "PVEC_PROCESS": "struct Lisp_Process",
+        "PVEC_BOOL_VECTOR": "struct Lisp_Bool_Vector",
+        "PVEC_BUFFER": "struct buffer",
+        "PVEC_HASH_TABLE": "struct Lisp_Hash_Table",
+        "PVEC_TERMINAL": "struct terminal",
+        "PVEC_WINDOW_CONFIGURATION": "struct save_window_data",
+        "PVEC_SUBR": "struct Lisp_Subr",
+        "PVEC_OTHER": "void",
+        "PVEC_XWIDGET": "void",
+        "PVEC_XWIDGET_VIEW": "void",
+        "PVEC_THREAD": "struct thread_state",
+        "PVEC_MUTEX": "Lisp_Mutex",
+        "PVEC_CONDVAR": "Lisp_CondVar",
+        "PVEC_MODULE_FUNCTION": "struct Lisp_Module_Function",
+        "PVEC_NATIVE_COMP_UNIT": "struct Lisp_Native_Comp_Unit",
+        "PVEC_SQLITE": "struct Lisp_Sqlite",
+        "PVEC_COMPILED": "struct Lisp_Vector",
+        "PVEC_CHAR_TABLE": "struct Lisp_Vector",
+        "PVEC_SUB_CHAR_TABLE": "void",
+        "PVEC_RECORD": "struct Lisp_Vector",
+        "PVEC_FONT": "struct font",
+        "PVEC_NORMAL_VECTOR": "struct Lisp_Vector"
+    }
+
+    # Object construction/initialization.
+    def __init__(self, lisp_obj):
+        self.frame = lisp_obj.GetFrame()
+        self.lisp_obj = lisp_obj
+        self.unsigned = lisp_obj.GetValueAsUnsigned()
+        self.lisp_type = None
+        self.pvec_type = None
+        self.value = None
+        self.init_lisp_types()
+        self.init_values()
+
+    # Initialize self.lisp_type to the C Lisp_Type enumerator of the
+    # Lisp_Object, as a string.  Initialize self.pvec_type likewise to
+    # the pvec_type enumerator if the object is a vector-like, as a
+    # string.
+    def init_lisp_types(self):
+        t = self.eval(f"(enum Lisp_Type)"
+                      f"((EMACS_INT) {self.unsigned} "
+                      f"& (1 << GCTYPEBITS) - 1)")
+        self.lisp_type = enumerator_name(t)
+        if self.lisp_type == "Lisp_Vectorlike":
+            self.pvec_type = "PVEC_NORMAL_VECTOR"
+            vector = self.get_lisp_pointer("struct Lisp_Vector")
+            size = vector.GetValueForExpressionPath("->header.size")
+            size = size.GetValueAsUnsigned()
+            pseudo = self.eval(f"{size} & PSEUDOVECTOR_FLAG")
+            if pseudo.GetValueAsUnsigned() != 0:
+                typ = self.eval(
+                    f"(enum pvec_type) (({size} "
+                    f"& More_Lisp_Bits::PVEC_TYPE_MASK) "
+                    f">> More_Lisp_Bits::PSEUDOVECTOR_AREA_BITS)")
+                self.pvec_type = enumerator_name(typ)
+
+    # Initialize self.value according to lisp_type and pvec_type.
+    def init_values(self):
+        if self.lisp_type == "Lisp_Symbol":
+            offset = self.get_lisp_pointer("char").GetValueAsUnsigned()
+            self.value = self.eval(f"(struct Lisp_Symbol *)"
+                                   f" ((char *) &lispsym + {offset})")
+        elif self.lisp_type == "Lisp_String":
+            self.value = self.get_lisp_pointer("struct Lisp_String")
+        elif self.lisp_type == "Lisp_Vectorlike":
+            c_type = Lisp_Object.pvec2type[self.pvec_type]
+            self.value = self.get_lisp_pointer(c_type)
+        elif self.lisp_type == "Lisp_Cons":
+            self.value = self.get_lisp_pointer("struct Lisp_Cons")
+        elif self.lisp_type == "Lisp_Float":
+            self.value = self.get_lisp_pointer("struct Lisp_Float")
+        elif self.lisp_type in ("Lisp_Int0", "Lisp_Int1"):
+            self.value = self.eval(f"((EMACS_INT) {self.unsigned}) "
+                                   f">> (GCTYPEBITS - 1)")
+        else:
+            assert False, "Unknown Lisp type"
+
+    # Create an SBValue for EXPR with name NAME.
+    def create_value(self, name, expr):
+        return self.lisp_obj.CreateValueFromExpression(name, expr)
+
+    # Evaluate EXPR in the context of the current frame.
+    def eval(self, expr):
+        return self.frame.EvaluateExpression(expr)
+
+    # Return an SBValue for this object denoting a pointer of type
+    # TYP*.
+    def get_lisp_pointer(self, typ):
+        return self.eval(f"({typ}*) (((EMACS_INT) "
+                         f"{self.unsigned}) & VALMASK)")
+
+    # If this is a Lisp_String, return an SBValue for its string data.
+    # Return None otherwise.
+    def get_string_data(self):
+        if self.lisp_type == "Lisp_String":
+            return self.value.GetValueForExpressionPath("->u.s.data")
+        return None
+
+    # if this is a Lisp_Symbol, return an SBBalue for its name.
+    # Return None otherwise.
+    def get_symbol_name(self):
+        if self.lisp_type == "Lisp_Symbol":
+            name = self.value.GetValueForExpressionPath("->u.s.name")
+            return Lisp_Object(name).get_string_data()
+        return None
+
+    # Return a summary string for this object.
+    def summary(self):
+        return str(self.value)
+
 
 ########################################################################
 #                           LLDB Commands
@@ -101,16 +174,14 @@ def xbacktrace(debugger, command, ctx, result, 
internal_dict):
         s = frame.EvaluateExpression(f"current_thread->m_specpdl[{i}]")
         kind = enumerator_name(s.GetChildMemberWithName("kind"))
         if kind == "SPECPDL_BACKTRACE":
-            function = s.GetValueForExpressionPath(".bt.function")
-            function_type = enumerator_name(get_lisp_type(function))
-            if function_type == "Lisp_Symbol":
-                sym_name = get_lisp_symbol_name(function)
+            function = Lisp_Object(s.GetValueForExpressionPath(".bt.function"))
+            if function.lisp_type == "Lisp_Symbol":
+                sym_name = function.get_symbol_name()
                 result.AppendMessage(str(sym_name))
-            elif function_type == "Lisp_Vectorlike":
-                subtype = get_lisp_type_or_vectorlike(function)
-                result.AppendMessage(str(subtype))
+            elif function.lisp_type == "Lisp_Vectorlike":
+                result.AppendMessage(function.pvec_type)
             else:
-                result.AppendMessage(function_type)
+                result.AppendMessage(function.lisp_type)
 
 def xdebug_print(debugger, command, result, internal_dict):
     """Print Lisp_Objects using safe_debug_print()"""
@@ -121,18 +192,8 @@ def xdebug_print(debugger, command, result, internal_dict):
 #                             Formatters
 ########################################################################
 
-# Return a type summary for Lisp_Objects.
-def format_Lisp_Object(obj, internal_dict):
-    lisp_type = get_lisp_type_or_vectorlike(obj)
-    kind = enumerator_name(lisp_type)
-    summary = "-> "
-    if kind == "PVEC_FRAME":
-        ptr = get_lisp_pointer(obj, "struct frame")
-        summary += str(ptr)
-    elif kind == "PVEC_WINDOW":
-        ptr = get_lisp_pointer(obj, "struct window")
-        summary += str(ptr)
-    return summary
+def type_summary_Lisp_Object(obj, internal_dict):
+    return "-> " + Lisp_Object(obj).summary()
 
 
 ########################################################################
@@ -155,11 +216,15 @@ def define_command (debugger, function):
     if not define("--overwrite"):
         define("")
 
-# Define Python FUNCTION as an LLDB type formatter.
-def define_formatter(debugger, regex, function):
+# Define Python FUNCTION as an LLDB type summary provider for types
+# matching REGEX.  Type summaries defined here are defined in the
+# category Emacs, and can be seen with 'type summary list -w Emacs',
+# and deleted in a similar way.
+def define_type_summary(debugger, regex, function):
     python_function = __name__ + "." + function.__name__
     debugger.HandleCommand(f"type summary add "
                            f"--cascade true "
+                           f"--category Emacs "
                            f'--regex "{regex}" '
                            f"--python-function {python_function}")
 
@@ -167,7 +232,7 @@ def define_formatter(debugger, regex, function):
 def __lldb_init_module(debugger, internal_dict):
     define_command(debugger, xbacktrace)
     define_command(debugger, xdebug_print)
-    define_formatter(debugger, "Lisp_Object", format_Lisp_Object)
+    define_type_summary(debugger, "Lisp_Object", type_summary_Lisp_Object)
     print('Emacs debugging support has been installed.')
 
 # end.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]