Compare commits

...

7 commits

Author SHA1 Message Date
Zach Shaftel
0cb1df1edd Store the bytecode offset in thread_state
* src/lisp.h:
* src/eval.c (backtrace_byte_offset): Remove global variable, and
put it...

* src/thread.h (thread_state): ...in here as
m_backtrace_byte_offset, and define backtrace_byte_offset as a
macro that points to it.

* src/bytecode.c (UPDATE_OFFSET): Move out of #ifdef
BYTE_CODE_THREADED.
2020-06-26 20:05:16 -04:00
Zach Shaftel
58e112fe18 Properly align offset in backtrace
* lisp/emacs-lisp/backtrace.el (backtrace--print-flags): Use format
width specifier to line up the flags and offset nicely.
2020-06-26 20:05:11 -04:00
rocky
afa6a9733e Merge feature/zach-soc-bytecode-in-traceback 2020-06-26 19:40:11 -04:00
Zach Shaftel
ef71dc437f Print offset of each backtrace frame 2020-05-01 14:56:46 -04:00
Zach Shaftel
077acd3a5f Only print offset for byte-compiled functions 2020-04-29 13:54:29 -04:00
Zach Shaftel
11b403cb23 Print byte offset of error in backtrace 2020-04-29 13:13:44 -04:00
rocky
e5734bef90 Experiment giving bytecode in traceback...
This commit only changes the behavior when `(cdr)` when it is not
given a `cons` node, in order to give some quick idea of how adding
more traceback information might work.

Here's how to see/use. Build this code.

Byte-compile this buggy function in `/tmp/foo.el`
with (byte-compile-file)
```lisp
(defun foo()
  (setq x 5)
  (cdr 'b)
  )
```

```
(load-file "/tmp/foo.elc")
(foo)
```

You should see:

```
Debugger entered--Lisp error: (wrong-type-argument listp b 3)
                                        this is the offset ^
  foo()
  eval((foo) nil)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  call-interactively(eval-last-sexp nil nil)
  command-execute(eval-last-sexp)
```

Compare against disassembly:

```
byte code for foo:
  args: nil
0	constant  5
1	varset	  x
2	constant  b
3	cdr
^^^ offset from above
4	return
```

You can try with other offsets such as by removing the `(setq x 5)`
and you'll see offset 1 instead.

Right now, we just pass to `signal` bytecode offset. More elaborate would be
to pass the code object and its offset. Even more elaborate schemes
could be imagined.
2020-04-27 15:14:12 -04:00
5 changed files with 39 additions and 9 deletions

View file

@ -257,7 +257,7 @@ frames where the source code location is known.")
map)
"Local keymap for `backtrace-mode' buffers.")
(defconst backtrace--flags-width 2
(defconst backtrace--flags-width 7
"Width in characters of the flags for a backtrace frame.")
;;; Navigation and Text Properties
@ -746,11 +746,14 @@ property for use by navigation."
"Print the flags of a backtrace FRAME if enabled in VIEW."
(let ((beg (point))
(flag (plist-get (backtrace-frame-flags frame) :debug-on-exit))
(source (plist-get (backtrace-frame-flags frame) :source-available)))
(source (plist-get (backtrace-frame-flags frame) :source-available))
(offset (plist-get (backtrace-frame-flags frame) :bytecode-offset))
;; right justify and pad the offset (or the empty string)
(offset-format (format "%%%ds " (- backtrace--flags-width 3))))
(when (plist-get view :show-flags)
(when source (insert ">"))
(when flag (insert "*")))
(insert (make-string (- backtrace--flags-width (- (point) beg)) ?\s))
(insert (if source ">" " "))
(insert (if flag "*" " "))
(insert (format offset-format (or offset ""))))
(put-text-property beg (point) 'backtrace-section 'func)))
(defun backtrace--print-func-and-args (frame _view)

View file

@ -311,6 +311,10 @@ enum byte_code_op
#define TOP (*top)
/* Update the thread's bytecode offset, just before NEXT. */
#define UPDATE_OFFSET (backtrace_byte_offset = pc - bytestr_data)
DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0,
doc: /* Function used internally in byte-compiled code.
The first argument, BYTESTR, is a string of byte code;
@ -430,7 +434,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
/* NEXT is invoked at the end of an instruction to go to the
next instruction. It is either a computed goto, or a
plain break. */
#define NEXT goto *(targets[op = FETCH])
#define NEXT UPDATE_OFFSET; goto *(targets[op = FETCH])
/* FIRST is like NEXT, but is only used at the start of the
interpreter body. In the switch-based interpreter it is the
switch, so the threaded definition must include a semicolon. */
@ -1448,7 +1452,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
unbind_to (count, Qnil);
error ("binding stack not balanced (serious byte compiler bug)");
}
backtrace_byte_offset = -1;
Lisp_Object result = TOP;
SAFE_FREE ();
return result;

View file

@ -137,6 +137,13 @@ backtrace_args (union specbinding *pdl)
return pdl->bt.args;
}
static int
backtrace_bytecode_offset (union specbinding *pdl)
{
eassert (pdl->kind == SPECPDL_BACKTRACE);
return pdl->bt.bytecode_offset;
}
static bool
backtrace_debug_on_exit (union specbinding *pdl)
{
@ -335,9 +342,7 @@ call_debugger (Lisp_Object arg)
redisplay, which necessarily leads to display problems. */
specbind (Qinhibit_eval_during_redisplay, Qt);
#endif
val = apply1 (Vdebugger, arg);
/* Interrupting redisplay and resuming it later is not safe under
all circumstances. So, when the debugger returns, abort the
interrupted redisplay by going back to the top-level. */
@ -2149,6 +2154,10 @@ record_in_backtrace (Lisp_Object function, Lisp_Object *args, ptrdiff_t nargs)
specpdl_ptr->bt.function = function;
current_thread->stack_top = specpdl_ptr->bt.args = args;
specpdl_ptr->bt.nargs = nargs;
union specbinding *nxt = specpdl_ptr;
nxt = backtrace_next(nxt);
if (nxt->kind == SPECPDL_BACKTRACE)
nxt->bt.bytecode_offset = backtrace_byte_offset;
grow_specpdl ();
return count;
@ -3650,6 +3659,10 @@ backtrace_frame_apply (Lisp_Object function, union specbinding *pdl)
if (backtrace_debug_on_exit (pdl))
flags = list2 (QCdebug_on_exit, Qt);
int off = backtrace_bytecode_offset (pdl);
if (off > 0)
flags = Fcons (QCbytecode_offset, Fcons (make_fixnum (off), flags));
if (backtrace_nargs (pdl) == UNEVALLED)
return call4 (function, Qnil, backtrace_function (pdl), *backtrace_args (pdl), flags);
else
@ -4237,6 +4250,7 @@ alist of active lexical bindings. */);
defsubr (&Sfetch_bytecode);
defsubr (&Sbacktrace_debug);
DEFSYM (QCdebug_on_exit, ":debug-on-exit");
DEFSYM (QCbytecode_offset, ":bytecode-offset");
defsubr (&Smapbacktrace);
defsubr (&Sbacktrace_frame_internal);
defsubr (&Sbacktrace_frames_from_thread);

View file

@ -3230,6 +3230,7 @@ union specbinding
Lisp_Object function;
Lisp_Object *args;
ptrdiff_t nargs;
int bytecode_offset;
} bt;
};
@ -3280,6 +3281,9 @@ struct handler
enum nonlocal_exit nonlocal_exit;
Lisp_Object val;
/* The bytecode offset where the error occurred. */
int bytecode_offset;
struct handler *next;
struct handler *nextfree;

View file

@ -103,6 +103,11 @@ struct thread_state
union specbinding *m_specpdl_ptr;
#define specpdl_ptr (current_thread->m_specpdl_ptr)
/* The offset of the current op of the byte-code function being
executed. */
int m_backtrace_byte_offset;
#define backtrace_byte_offset (current_thread->m_backtrace_byte_offset)
/* Depth in Lisp evaluations and function calls. */
intmax_t m_lisp_eval_depth;
#define lisp_eval_depth (current_thread->m_lisp_eval_depth)