From: Gerd Möllmann Date: Mon, 16 Oct 2023 08:12:10 +0000 (+0200) Subject: ; LLDB support cleanup and extension X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=c3038bf5e1d79c3dfa83717a5a61ecc86116f04a;p=emacs.git ; LLDB support cleanup and extension --- diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py index 24b127a1fb9..a4f066b79de 100644 --- a/etc/emacs_lldb.py +++ b/etc/emacs_lldb.py @@ -78,22 +78,22 @@ class Lisp_Object: # Object construction/initialization. def __init__(self, lisp_obj): - self.lisp_obj = lisp_obj - self.frame = lisp_obj.GetFrame() + self.tagged = lisp_obj + self.unsigned = None self.lisp_type = None self.pvec_type = None - self.value = None + self.untagged = None self.init_unsigned() self.init_lisp_types() self.init_values() def init_unsigned(self): - if self.lisp_obj.GetType().GetTypeClass() == lldb.eTypeClassStruct: + if self.tagged.GetType().GetTypeClass() == lldb.eTypeClassStruct: # Lisp_Object is actually a struct. - lisp_word = self.lisp_obj.GetValueForExpressionPath(".i") + lisp_word = self.tagged.GetValueForExpressionPath(".i") self.unsigned = lisp_word.GetValueAsUnsigned() else: - self.unsigned = self.lisp_obj.GetValueAsUnsigned() + self.unsigned = self.tagged.GetValueAsUnsigned() # Initialize self.lisp_type to the C Lisp_Type enumerator of the # Lisp_Object, as a string. Initialize self.pvec_type likewise to @@ -117,40 +117,38 @@ class Lisp_Object: f">> More_Lisp_Bits::PSEUDOVECTOR_AREA_BITS)") self.pvec_type = enumerator_name(typ) - # Initialize self.value according to lisp_type and pvec_type. + # Initialize self.untagged 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 *)" + self.untagged = self.eval(f"(struct Lisp_Symbol *)" f" ((char *) &lispsym + {offset})", True) elif self.lisp_type == "Lisp_String": - self.value = self.get_lisp_pointer("struct Lisp_String", True) + self.untagged = self.get_lisp_pointer("struct Lisp_String", True) elif self.lisp_type == "Lisp_Vectorlike": c_type = Lisp_Object.pvec2type[self.pvec_type] - self.value = self.get_lisp_pointer(c_type, True) + self.untagged = self.get_lisp_pointer(c_type, True) elif self.lisp_type == "Lisp_Cons": - self.value = self.get_lisp_pointer("struct Lisp_Cons", True) + self.untagged = self.get_lisp_pointer("struct Lisp_Cons", True) elif self.lisp_type == "Lisp_Float": - self.value = self.get_lisp_pointer("struct Lisp_Float", True) + self.untagged = self.get_lisp_pointer("struct Lisp_Float", True) elif self.lisp_type in ("Lisp_Int0", "Lisp_Int1"): - self.value = self.eval(f"((EMACS_INT) {self.unsigned}) " - f">> (GCTYPEBITS - 1)", - True) + self.untagged = self.eval(f"((EMACS_INT) {self.unsigned}) " + f">> (GCTYPEBITS - 1)", True) + elif self.lisp_type == "Lisp_Type_Unused0": + self.untagged = self.unsigned 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) + assert False, f"Unknown Lisp type {self.lisp_type}" # Evaluate EXPR in the context of the current frame. def eval(self, expr, make_var=False): + frame = self.tagged.GetFrame() if make_var: - return self.frame.EvaluateExpression(expr) + return frame.EvaluateExpression(expr) options = lldb.SBExpressionOptions() options.SetSuppressPersistentResult(True) - return self.frame.EvaluateExpression(expr, options) + return frame.EvaluateExpression(expr, options) # Return an SBValue for this object denoting a pointer of type # TYP*. @@ -163,20 +161,20 @@ class Lisp_Object: # Return None otherwise. def get_string_data(self): if self.lisp_type == "Lisp_String": - return self.value.GetValueForExpressionPath("->u.s.data") + return self.untagged.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") + name = self.untagged.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) + return str(self.untagged) ######################################################################## @@ -205,6 +203,15 @@ def xdebug_print(debugger, command, result, internal_dict): """Print Lisp_Objects using safe_debug_print()""" debugger.HandleCommand(f"expr safe_debug_print({command})") +def xcomplete(debugger, command, result, internal_dict): + """Print completions for COMMAND.""" + interpreter = debugger.GetCommandInterpreter() + string_list = lldb.SBStringList() + interpreter.HandleCompletion(command, len(command), len(command), + -1, string_list) + for i in range(string_list.GetSize()): + result.AppendMessage(string_list.GetStringAtIndex(i)) + ######################################################################## # Formatters @@ -213,40 +220,49 @@ def xdebug_print(debugger, command, result, internal_dict): def type_summary_Lisp_Object(obj, internal_dict): return Lisp_Object(obj).summary() -# Don't know at the moment how to use this outside of the LLDB gui -# command. And it's still incomplete. class Lisp_Object_Provider: + """Synthetic children provider for Lisp_Objects. + Supposedly only used by 'frame variable', where -P can be used + to specify a printing depth. """ def __init__(self, valobj, internal_dict): self.valobj = valobj - self.lisp_obj = Lisp_Object(valobj) - self.child = None + self.children = {} def update(self): - if self.lisp_obj.lisp_type == "Lisp_Symbol": - self.child = self.lisp_obj.get_symbol_name().Clone("name") - self.child.SetSyntheticChildGenerated(True) - elif self.lisp_obj.lisp_type == "Lisp_String": - self.child = self.lisp_obj.get_string_data().Clone("data") - self.child.SetSyntheticChildGenerated(True) - else: - self.child = self.lisp_obj.value.Clone("untagged") - self.child.SetSyntheticChildGenerated(True) - - def has_children(self): - return True + lisp_obj = Lisp_Object(self.valobj) + lisp_type = lisp_obj.lisp_type + try: + if lisp_type == "Lisp_Symbol": + child = lisp_obj.get_symbol_name() + self.children["name"] = child + elif lisp_type == "Lisp_String": + child = lisp_obj.get_string_data() + self.children["data"] = child + elif lisp_type == "Lisp_Cons": + car = lisp_obj.untagged.GetValueForExpressionPath("->u.s.car") + cdr = lisp_obj.untagged.GetValueForExpressionPath("->u.s.u.cdr") + self.children["car"] = car + self.children["cdr"] = cdr + else: + self.children["untagged"] = lisp_obj.untagged + except: + print(f"*** exception in child provider update for {lisp_type}") + pass def num_children(self): - return 1 + return len(self.children) def get_child_index(self, name): - return 0 + index = 0 + for child_name, child in self.children: + if child_name == name: + return index + index = index + 1 + return -1 - # This works insofar as struct frame * works, but it doesn't work - # Lisp_Symbol, for example. def get_child_at_index(self, index): - if index != 0: - return None - return self.child + key = list(self.children)[index] + return self.children[key] ######################################################################## @@ -300,6 +316,7 @@ def enable_type_category(debugger, category): def __lldb_init_module(debugger, internal_dict): define_command(debugger, xbacktrace) define_command(debugger, xdebug_print) + define_command(debugger, xcomplete) define_type_summary(debugger, "Lisp_Object", type_summary_Lisp_Object) define_type_synthetic(debugger, "Lisp_Object", Lisp_Object_Provider) enable_type_category(debugger, "Emacs")