diff options
| author | Mattias EngdegÄrd | 2024-09-09 10:23:46 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-09-09 10:30:02 +0200 |
| commit | 87daaaf9a463720f2ec80201d8f1e41aa29bd7ce (patch) | |
| tree | f5334f2695df4ff3997b71fe1c8fbd4bdf92208e | |
| parent | 95371fa754260199a6ea3428721270a89c341928 (diff) | |
| download | emacs-87daaaf9a463720f2ec80201d8f1e41aa29bd7ce.tar.gz emacs-87daaaf9a463720f2ec80201d8f1e41aa29bd7ce.zip | |
Speed up LLDB support for debugging Emacs
* etc/emacs_lldb.py (Lisp_Object):
Perform some numeric operations in Python instead of invoking LLDB
for evaluation. Add lots of caches.
| -rw-r--r-- | etc/emacs_lldb.py | 117 |
1 files changed, 79 insertions, 38 deletions
diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py index 219361faffd..8393fccf467 100644 --- a/etc/emacs_lldb.py +++ b/etc/emacs_lldb.py | |||
| @@ -104,62 +104,103 @@ class Lisp_Object: | |||
| 104 | # the pvec_type enumerator if the object is a vector-like, as a | 104 | # the pvec_type enumerator if the object is a vector-like, as a |
| 105 | # string. | 105 | # string. |
| 106 | def init_lisp_types(self): | 106 | def init_lisp_types(self): |
| 107 | t = self.eval(f"(enum Lisp_Type)" | 107 | GCTYPEBITS = self.unsigned_const('GCTYPEBITS') |
| 108 | f"((EMACS_INT) {self.unsigned} " | 108 | self.lisp_type = self.tag_name(self.unsigned |
| 109 | f"& (1 << GCTYPEBITS) - 1)") | 109 | & ((1 << GCTYPEBITS) - 1)) |
| 110 | self.lisp_type = enumerator_name(t) | ||
| 111 | if self.lisp_type == "Lisp_Vectorlike": | 110 | if self.lisp_type == "Lisp_Vectorlike": |
| 112 | self.pvec_type = "PVEC_NORMAL_VECTOR" | 111 | self.pvec_type = "PVEC_NORMAL_VECTOR" |
| 113 | vector = self.get_lisp_pointer("struct Lisp_Vector") | 112 | vector = self.get_lisp_pointer("struct Lisp_Vector") |
| 114 | size = vector.GetValueForExpressionPath("->header.size") | 113 | size = vector.GetValueForExpressionPath("->header.size") |
| 115 | size = size.GetValueAsUnsigned() | 114 | size = size.GetValueAsUnsigned() |
| 116 | pseudo = self.eval(f"{size} & PSEUDOVECTOR_FLAG") | 115 | PSEUDOVECTOR_FLAG = self.unsigned_const('PSEUDOVECTOR_FLAG') |
| 117 | if pseudo.GetValueAsUnsigned() != 0: | 116 | if size & PSEUDOVECTOR_FLAG: |
| 118 | typ = self.eval( | 117 | PVEC_TYPE_MASK = self.unsigned_const( |
| 119 | f"(enum pvec_type) (({size} " | 118 | 'More_Lisp_Bits::PVEC_TYPE_MASK') |
| 120 | f"& More_Lisp_Bits::PVEC_TYPE_MASK) " | 119 | PSEUDOVECTOR_AREA_BITS = self.unsigned_const( |
| 121 | f">> More_Lisp_Bits::PSEUDOVECTOR_AREA_BITS)") | 120 | 'More_Lisp_Bits::PSEUDOVECTOR_AREA_BITS') |
| 122 | self.pvec_type = enumerator_name(typ) | 121 | pvec = (size & PVEC_TYPE_MASK) >> PSEUDOVECTOR_AREA_BITS |
| 122 | self.pvec_type = self.pvec_name(pvec) | ||
| 123 | 123 | ||
| 124 | # Initialize self.untagged according to lisp_type and pvec_type. | 124 | # Initialize self.untagged according to lisp_type and pvec_type. |
| 125 | def init_values(self): | 125 | def init_values(self): |
| 126 | if self.lisp_type == "Lisp_Symbol": | 126 | lt = self.lisp_type |
| 127 | if lt == "Lisp_Symbol": | ||
| 127 | offset = self.get_lisp_pointer("char").GetValueAsUnsigned() | 128 | offset = self.get_lisp_pointer("char").GetValueAsUnsigned() |
| 128 | self.untagged = self.eval(f"(struct Lisp_Symbol *)" | 129 | self.untagged = self.eval( |
| 129 | f" ((char *) &lispsym + {offset})", | 130 | f"(struct Lisp_Symbol *)((char *)&lispsym + {offset})") |
| 130 | True) | 131 | elif lt == "Lisp_String": |
| 131 | elif self.lisp_type == "Lisp_String": | 132 | self.untagged = self.get_lisp_pointer("struct Lisp_String") |
| 132 | self.untagged = self.get_lisp_pointer("struct Lisp_String", True) | 133 | elif lt == "Lisp_Vectorlike": |
| 133 | elif self.lisp_type == "Lisp_Vectorlike": | ||
| 134 | c_type = Lisp_Object.pvec2type[self.pvec_type] | 134 | c_type = Lisp_Object.pvec2type[self.pvec_type] |
| 135 | self.untagged = self.get_lisp_pointer(c_type, True) | 135 | self.untagged = self.get_lisp_pointer(c_type) |
| 136 | elif self.lisp_type == "Lisp_Cons": | 136 | elif lt == "Lisp_Cons": |
| 137 | self.untagged = self.get_lisp_pointer("struct Lisp_Cons", True) | 137 | self.untagged = self.get_lisp_pointer("struct Lisp_Cons") |
| 138 | elif self.lisp_type == "Lisp_Float": | 138 | elif lt == "Lisp_Float": |
| 139 | self.untagged = self.get_lisp_pointer("struct Lisp_Float", True) | 139 | self.untagged = self.get_lisp_pointer("struct Lisp_Float") |
| 140 | elif self.lisp_type in ("Lisp_Int0", "Lisp_Int1"): | 140 | elif lt in ("Lisp_Int0", "Lisp_Int1"): |
| 141 | self.untagged = self.eval(f"((EMACS_INT) {self.unsigned}) " | 141 | GCTYPEBITS = self.unsigned_const('GCTYPEBITS') |
| 142 | f">> (GCTYPEBITS - 1)", True) | 142 | x = self.unsigned >> (GCTYPEBITS - 1) |
| 143 | elif self.lisp_type == "Lisp_Type_Unused0": | 143 | self.untagged = self.eval(f"(EMACS_INT){x})") |
| 144 | elif lt == "Lisp_Type_Unused0": | ||
| 144 | self.untagged = self.unsigned | 145 | self.untagged = self.unsigned |
| 145 | else: | 146 | else: |
| 146 | assert False, f"Unknown Lisp type {self.lisp_type}" | 147 | assert False, f"Unknown Lisp type {self.lisp_type}" |
| 147 | 148 | ||
| 149 | # Get a numeric constant (unsigned). | ||
| 150 | const_cache = {} | ||
| 151 | def unsigned_const(self, name): | ||
| 152 | val = self.const_cache.get(name) | ||
| 153 | if val is None: | ||
| 154 | frame = self.tagged.GetFrame() | ||
| 155 | val = frame.EvaluateExpression(name).GetValueAsUnsigned() | ||
| 156 | self.const_cache[name] = val | ||
| 157 | return val | ||
| 158 | |||
| 159 | # Get the name of a Lisp_Object tag value, like "Lisp_String". | ||
| 160 | tag_cache = {} | ||
| 161 | def tag_name(self, tag): | ||
| 162 | name = self.tag_cache.get(tag) | ||
| 163 | if name is None: | ||
| 164 | frame = self.tagged.GetFrame() | ||
| 165 | val = frame.EvaluateExpression(f"(enum Lisp_Type){tag}") | ||
| 166 | name = enumerator_name(val) | ||
| 167 | self.tag_cache[tag] = name | ||
| 168 | return name | ||
| 169 | |||
| 170 | # Get the name of a pseudovector type tag, like "PVEC_HASH_TABLE". | ||
| 171 | pvec_cache = {} | ||
| 172 | def pvec_name(self, pvec): | ||
| 173 | name = self.pvec_cache.get(pvec) | ||
| 174 | if name is None: | ||
| 175 | frame = self.tagged.GetFrame() | ||
| 176 | val = frame.EvaluateExpression(f"(enum pvec_type){pvec}") | ||
| 177 | name = enumerator_name(val) | ||
| 178 | self.pvec_cache[pvec] = name | ||
| 179 | return name | ||
| 180 | |||
| 148 | # Evaluate EXPR in the context of the current frame. | 181 | # Evaluate EXPR in the context of the current frame. |
| 149 | def eval(self, expr, make_var=False): | 182 | eval_cache = {} |
| 150 | frame = self.tagged.GetFrame() | 183 | def eval(self, expr): |
| 151 | if make_var: | 184 | val = self.eval_cache.get(expr) |
| 152 | return frame.EvaluateExpression(expr) | 185 | if val is None: |
| 153 | options = lldb.SBExpressionOptions() | 186 | frame = self.tagged.GetFrame() |
| 154 | options.SetSuppressPersistentResult(True) | 187 | val = frame.EvaluateExpression(expr) |
| 155 | return frame.EvaluateExpression(expr, options) | 188 | self.eval_cache[expr] = val |
| 189 | return val | ||
| 156 | 190 | ||
| 157 | # Return an SBValue for this object denoting a pointer of type | 191 | # Return an SBValue for this object denoting a pointer of type |
| 158 | # TYP*. | 192 | # TYP*. |
| 159 | def get_lisp_pointer(self, typ, make_var=False): | 193 | lisp_ptr_cache = {} |
| 160 | return self.eval(f"({typ}*) (((EMACS_INT) " | 194 | def get_lisp_pointer(self, typ): |
| 161 | f"{self.unsigned}) & VALMASK)", | 195 | uns = self.unsigned |
| 162 | make_var) | 196 | ptr = self.lisp_ptr_cache.get((uns, typ)) |
| 197 | if ptr is None: | ||
| 198 | VALMASK = self.unsigned_const('VALMASK') | ||
| 199 | frame = self.tagged.GetFrame() | ||
| 200 | ptr = frame.EvaluateExpression( | ||
| 201 | f"({typ}*)(EMACS_INT){uns & VALMASK}") | ||
| 202 | self.lisp_ptr_cache[(uns, typ)] = ptr | ||
| 203 | return ptr | ||
| 163 | 204 | ||
| 164 | # If this is a Lisp_String, return an SBValue for its string data. | 205 | # If this is a Lisp_String, return an SBValue for its string data. |
| 165 | # Return None otherwise. | 206 | # Return None otherwise. |