From: "Gerd Möllmann" <gerd.moellmann@gmail.com>
To: 56495@debbugs.gnu.org
Subject: bug#56495: 29.0.50; Support for debugging Emacs with LLDB
Date: Mon, 11 Jul 2022 10:13:35 +0200 [thread overview]
Message-ID: <AAB63EE4-18DD-40D7-A64E-DEB6729B60B3@gmail.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 629 bytes --]
My system, macOS with Apple M1 chip, is currently not supported by GDB.
To quote gdb-devel, "lldb is the way to go" to debug Emacs for me.
Attached patch adds rather limited support for that. Limited by
- the fact that I don't know LLDB,
- that I don't know LLDB's Python API,
- that I'm not a Python programmer,
- that the Python API documentation is pretty lacking in itself,
- that I didn't implement support for ENABLE_CHECKING and what else
might change Lisp_Object layout
So please bear with me.
Anyway, at least displaying some Lisp_Objects with 'p obj' seems to
work, and 'xbacktrace' seems to be working.
YMMV.
[-- Attachment #1.2: 0001-Support-for-debugging-Emacs-with-LLDB.patch --]
[-- Type: application/octet-stream, Size: 8978 bytes --]
From c5cfd261a549740a0619eb1854032778204dc51e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <gerd@gnu.org>
Date: Sun, 10 Jul 2022 13:35:32 +0200
Subject: [PATCH] Support for debugging Emacs with LLDB
* (src/.lldbinit): New file.
* (etc/emacs_lldb.py): Module loaded from .lldbinit.
---
etc/emacs_lldb.py | 166 ++++++++++++++++++++++++++++++++++++++++++++++
src/.lldbinit | 33 +++++++++
2 files changed, 199 insertions(+)
create mode 100644 etc/emacs_lldb.py
create mode 100644 src/.lldbinit
diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py
new file mode 100644
index 0000000000..3a9f17e020
--- /dev/null
+++ b/etc/emacs_lldb.py
@@ -0,0 +1,166 @@
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of GNU Emacs.
+#
+# GNU Emacs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Emacs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+# Load this module in LLDB with
+#
+# (lldb) command script import emacs_lldb
+#
+# Available commands start with 'x' and can be seen with
+#
+# (lldb) help
+
+import lldb
+
+\f
+########################################################################
+# 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.
+def enumerator_name(enum):
+ enumerators = enum.GetType().GetEnumMembers()
+ return enumerators[enum.GetValueAsUnsigned()].GetName()
+
+\f
+########################################################################
+# LLDB Commands
+########################################################################
+
+def xbacktrace(debugger, command, ctx, result, internal_dict):
+ """Print Emacs Lisp backtrace"""
+ frame = ctx.GetFrame()
+ n = frame.EvaluateExpression(
+ "current_thread->m_specpdl_ptr - current_thread->m_specpdl")
+ for i in reversed(range(0, n.GetValueAsUnsigned())):
+ 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)
+ result.AppendMessage(str(sym_name))
+ elif function_type == "Lisp_Vectorlike":
+ subtype = get_lisp_type_or_vectorlike(function)
+ result.AppendMessage(str(subtype))
+ else:
+ result.AppendMessage(function_type)
+
+def xdebug_print(debugger, command, result, internal_dict):
+ """Print Lisp_Objects using safe_debug_print()"""
+ debugger.HandleCommand(f"expr safe_debug_print({command})")
+
+\f
+########################################################################
+# 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
+
+\f
+########################################################################
+# Initialization
+########################################################################
+
+# Define Python FUNCTION as an LLDB command.
+def define_command (debugger, function):
+ lldb_command = function.__name__
+ python_function = __name__ + "." + function.__name__
+ debugger.HandleCommand(f"command script add "
+ f"--overwrite "
+ f"--function {python_function} "
+ f"{lldb_command}")
+
+# Define Python FUNCTION as an LLDB type formatter.
+def define_formatter(debugger, regex, function):
+ python_function = __name__ + "." + function.__name__
+ debugger.HandleCommand(f"type summary add "
+ f"--cascade true "
+ f'--regex "{regex}" '
+ f"--python-function {python_function}")
+
+# This function is called by LLDB to initialize the module.
+def __lldb_init_module(debugger, internal_dict):
+ define_command(debugger, xbacktrace)
+ define_command(debugger, xdebug_print)
+ define_formatter(debugger, "Lisp_Object", format_Lisp_Object)
+ print('Emacs debugging support has been installed.')
+
+# end.
diff --git a/src/.lldbinit b/src/.lldbinit
new file mode 100644
index 0000000000..617d63958b
--- /dev/null
+++ b/src/.lldbinit
@@ -0,0 +1,33 @@
+# -*- mode: shell-script -*-
+# Copyright (C) 1992-1998, 2000-2022 Free Software Foundation, Inc.
+#
+# This file is part of GNU Emacs.
+#
+# GNU Emacs is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Emacs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+#
+# Use 'lldb --local-init' or add to your ~/.lldbinit the line
+#
+# settings set target.load-cwd-lldbinit true
+#
+# Emacs-specific commands start with 'x'. Type 'help' to see all
+# commands. Type 'help <command>' to see help for a command
+# <command>.
+
+# Make Python find our files
+script -- sys.path.append('../etc')
+
+# Load our Python files
+command script import emacs_lldb
+
+# end.
--
2.37.0
[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 874 bytes --]
next reply other threads:[~2022-07-11 8:13 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-11 8:13 Gerd Möllmann [this message]
2022-07-11 9:18 ` bug#56495: 29.0.50; Support for debugging Emacs with LLDB Robert Pluim
2022-07-11 10:42 ` Gerd Möllmann
2022-07-11 10:56 ` Robert Pluim
2022-07-11 11:27 ` Gerd Möllmann
2022-07-11 12:28 ` Robert Pluim
2022-09-05 19:16 ` Lars Ingebrigtsen
2022-07-11 11:19 ` Eli Zaretskii
2022-07-11 11:31 ` Gerd Möllmann
2022-07-12 3:04 ` Richard Stallman
2022-07-12 3:15 ` Stefan Kangas
2022-07-14 3:10 ` Richard Stallman
2022-07-12 8:04 ` Gerd Möllmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=AAB63EE4-18DD-40D7-A64E-DEB6729B60B3@gmail.com \
--to=gerd.moellmann@gmail.com \
--cc=56495@debbugs.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).