Compare commits

...

11 commits

Author SHA1 Message Date
Zach Shaftel
bed4004fd3 Clean up before patch submission
* src/lisp.h (struct handler): Remove unused 'bytecode_offset' field,
which was added at some point while prototyping.

* src/bytecode.c (UPDATE_OFFSET): Subtract 1, so the offset is accurate.
2020-07-22 20:07:15 -04:00
Zach Shaftel
54b94af19d Only store offset when executing bytecode
* src/eval.c (record_in_backtrace): Use 'backtrace_top' instead of
'backtrace_next', and check that 'backtrace_byte_offset' > 0 before
calling it, so the specbinding stack isn't scanned just to store an
invalid offset.
2020-07-22 19:55:15 -04:00
Zach Shaftel
c0576f5acc Only print offset for byte-code functions
* lisp/emacs-lisp/backtrace.el (backtrace--print-flags): Check if the
function is compiled and only print the offset in that case.
2020-07-15 13:05:00 -04:00
rocky
9a36861ef6 Reduced bytecode offset update
This reduces bytecode-offset updates to happen only before a call.
2020-07-13 11:50:35 -04:00
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 6 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,16 @@ 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)))
(fun (ignore-errors (indirect-function (backtrace-frame-fun frame)))))
(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 (and (byte-code-function-p fun) 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 - 1)
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;
@ -618,6 +622,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
op -= Bcall;
docall:
{
UPDATE_OFFSET;
DISCARD (op);
#ifdef BYTE_CODE_METER
if (byte_metering_on && SYMBOLP (TOP))
@ -1448,7 +1453,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)
{
@ -2149,6 +2156,11 @@ 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;
if (backtrace_byte_offset > 0) {
union specbinding *nxt = backtrace_top ();
if (backtrace_p (nxt) && nxt->kind == SPECPDL_BACKTRACE)
nxt->bt.bytecode_offset = backtrace_byte_offset;
}
grow_specpdl ();
return count;
@ -3650,6 +3662,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 +4253,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;
};

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)