ref: daf109ca9fc190db105b7dc75e2bd84c13dba312
parent: 80771da12a271c80a9786f299ec464a7dbd11800
author: spew <spew@cbza.org>
date: Sun Apr 6 14:35:29 EDT 2025
lsd: switch to using strings to refer to symbols, various cleanups
--- a/src/plan9/lsd.c
+++ b/src/plan9/lsd.c
@@ -462,9 +462,12 @@
}
sl_purefn
-BUILTIN("lsd-ptrsize", lsd_ptrsize)
+BUILTIN("lsd-ptr", lsd_ptr)
{
+ sl_v ptrsym;
+
USED(args);
argcount(nargs, 0);
- return sizeof(void*) == 4 ? sl_u32sym : sl_u64sym;
+ ptrsym = sizeof(void*) == 4 ? sl_u32sym : sl_u64sym;
+ return sym_value(ptrsym);
}
--- a/src/plan9/lsd.sl
+++ b/src/plan9/lsd.sl
@@ -8,51 +8,65 @@
All registers are exposed as top-level symbols. The fields are
internal. The top-level symbol `registers` is a list of all
- available registers. To read the value of a register use `readreg`
+ available registers. To read the value of a register use `reg-read`
Examples:
- `(readreg AX)`"
+ `(reg-read AX)`"
:doc-group lsd
- :doc-see readreg
+ :doc-see reg-read
+ :doc-see registers
name type addr size)
-
+
(defstruct symbol
"A symbol of the process.
-
- Name is a string denoting the symbol, type is a character as
- described in a.out(6), and address is the location of the symbol in
- the process address space"
+
+ Name is a string denoting the symbol, type is a character as
+ described in a.out(6), and address is the location of the symbol in
+ the process address space"
:doc-group lsd
name type addr)
-
+
(defstruct global
"All the global symbols, separated into text and data symbols.
- The text and data fields are both tables from syms to symbols."
+ The text and data fields are both tables from strings to symbols."
:doc-group lsd
:doc-see symbol
text data)
-
+
(defstruct frame
"A stack frame.
-
- Sym is the enclosing function symbol and instruction address of the
- frame. Retpc is the return instruction address. Sp is the stack
- pointer value. Locals are all the local symbols."
+
+ Sym is the enclosing function symbol and instruction address of the
+ frame. Retpc is the return instruction address. Sp is the stack
+ pointer value. Locals are all the local symbols."
:doc-group lsd
:doc-see symbol
sym retpc sp locals)
+(def tracers (table
+ "386" (λ () (lsd-ctrace (curPC) (reg-read SP) (u64 0)))
+ "68020" (λ () (lsd-ctrace (curPC) (reg-read SP) (reg-read A7)))
+ "amd64" (λ () (lsd-ctrace (curPC) (reg-read SP) (u64 0)))
+ "arm" (λ () (lsd-ctrace (curPC) (reg-read SP) (reg-read R14)))
+ "arm64" (λ () (lsd-ctrace (curPC) (reg-read SP) (reg-read R30)))
+ "mips" (λ () (lsd-ctrace (curPC) (reg-read SP) (reg-read R31)))
+ "power" (λ () (lsd-ctrace (curPC) (reg-read SP) (reg-read LR)))
+ "power64" (λ () (lsd-ctrace (curPC) (reg-read SP) (reg-read LR)))))
+
(def coref NIL)
(def regsf NIL)
(def fpregsf NIL)
(def proc-stdin NIL)
(def pids NIL)
+(def pid -1)
(def bptbl (table))
+(def ctrace (get tracers (os-getenv "objtype")))
+(def ptr (lsd-ptr))
(def (procfile s . flags)
- (when (< pid 0) (error "no active pid"))
+ (when (< pid 0) (error "no active process"))
(let {[path (str "/proc/" pid "/" s)]}
(apply file (cons path flags))))
@@ -82,6 +96,10 @@
(def (start) (writectl "start"))
(def (startstop) (writectl "startstop") (readnote))
(def (stop) (writectl "stop") (readnote))
+(def (waitstop)
+ (unless (eq? (status) 'Stopped)
+ (princ "Waiting... " status "\n")
+ (stop)))
(def (follow addr)
"Return a list of the next possible executing instructions."
@@ -88,30 +106,30 @@
:doc-group lsd
(lsd-follow addr))
-(def (io-pread f off rest)
- (io-seek f off)
- (apply io-read (cons f rest)))
+(defmacro (io-pread f off . rest)
+ `(begin (io-seek ,f ,off)
+ (io-read ,f ,.rest)))
-(def (io-pwrite f off rest)
- (io-seek f off)
- (apply io-write (cons f rest))
- (io-flush f))
+(defmacro (io-pwrite f off . rest)
+ `(begin (io-seek ,f ,off)
+ (io-write ,f ,.rest)
+ (io-flush ,f)))
-(def (readcore addr . rest)
- (unless coref (error "not attached to proc"))
- (io-pread coref addr rest))
+(defmacro (core-read addr . rest)
+ `(begin (unless coref (error "not attached to proc"))
+ (io-pread coref ,addr ,.rest)))
-(def (writecore addr . rest)
- (unless coref (error "not attached to proc"))
- (io-pwrite coref addr rest))
+(defmacro (core-write addr . rest)
+ `(begin (unless coref (error "not attached to proc"))
+ (io-pwrite coref ,addr ,.rest)))
-(def (readreg reg)
+(def (reg-read reg)
"Read the value of a register.
Examples:
- (readreg AX) ; read the return register on amd64
- (readreg PC) ; read the current instruction address."
+ (reg-read AX) ; read the return register on amd64
+ (reg-read PC) ; read the current instruction address."
:doc-group lsd
:doc-see reg
:doc-see registers
@@ -119,44 +137,55 @@
(let {[f (case (reg-type reg)
((:gpreg) regsf)
((:fpreg) fpregsf))]}
- (io-pread f (reg-addr reg) (list (reg-size reg)))))
+ (io-pread f (reg-addr reg) (reg-size reg))))
-(def (symbol-read symbol . rest)
+(defmacro (symbol-read symbol . rest)
"Read the value from the core file at the symbol's address."
:doc-group lsd
- :doc-see sym-local
- :doc-see sym-global
- :doc-see sym-addr
- (unless coref (error "not attached to proc"))
- (apply readcore (cons (symbol-addr symbol) rest)))
-
-(def (loc->addr loc)
- (cond ((sym? loc) (symbol-addr
- (or (sym-local loc)
- (sym-global loc))))
- ((num? loc) (u64 loc))
- ((symbol? loc) (symbol-addr loc))
- (else (error "sym|num|symbol"))))
+ :doc-see local-symbol
+ :doc-see global-symbol
+ `(core-read (symbol-addr ,symbol) ,.rest))
-(def (read-loc loc sz)
- (readcore (loc->addr loc) sz))
+(def (str->symbol s)
+ (or (local-symbol s)
+ (global-symbol s)))
-(def (c-ptr loc) (read-loc loc ptrsz))
+(def (str->addr s (:str->symbol str->symbol))
+ "Return the address corresponding to a source code line or symbol.
+
+ Input is a string. By default str->symbol is used to lookup
+ symbols in the local stack frame and then the global text and data
+ symbol tables."
+ :doc-see loc->addr
+ :doc-see str->symbol
+ :doc-group lsd
+ (trycatch
+ (filepc s)
+ (λ (e) (when (eq? (car e) 'io-error) (raise e))
+ (let {[symb (symbol-addr (str->symbol s))]}
+ (if symb
+ (symbol-addr symb)
+ (error "could not find symbol " s))))))
-(def (c-int loc) (read-loc loc 's32))
+(def (loc->addr loc (:str->symbol str->symbol))
+ «Return the address of a location.
-(def c-long c-int)
+ A location refers to either
+ 1. A string that refers to a symbol in the process's
+ symbol table or call stack,
+ 2. A string of the form "file:line" used to look up
+ an instruction address corresponding to source code,
+ 3. A number which is an address in the process's address space,
+ 4. A symbol in which case the symbol's address is used.
-(def (c-uint loc) (read-loc loc 'u32))
+ By default str->symbol is used to find the corresponding symbol
+ which searches the local call stack then global text symbols then
+ global data symbols.»
+ (cond ((str? loc) (str->addr loc :str->symbol str->symbol))
+ ((num? loc) (ptr loc))
+ ((symbol? loc) (symbol-addr loc))
+ (else (error "str|num|symbol"))))
-(def (c-str loc)
- (def (go a)
- (let {[v (readcore a 'utf8)]}
- (if (= v (utf8 0))
- ()
- (cons v (go (1+ a))))))
- (apply arr (cons 'utf8 (go (c-ptr (loc->addr loc))))))
-
(def (hex n)
"Display an integer in hex format."
:doc-group lsd
@@ -167,70 +196,38 @@
:doc-group lsd
(str "0" (num->str n 8)))
-(def (bpsave a) (readcore a 'u8 (length bpinst)))
+(def (bpsave a) (core-read a 'u8 (length bpinst)))
-(let {[bp_init (λ (loc)
- (when (< pid 0) (error "no running process"))
- (unless (eq? (status) 'Stopped)
- (begin (princ "Waiting... " status "\n")
- (stop)))
- (cond ((sym? loc) (symbol-addr
- (get (global-text globals) loc)))
- ((num? loc) (u64 loc))
- ((symbol? loc) (symbol-addr loc))
- ((str? loc) (filepc loc))
- (else (error "sym|num|symbol|file:line"))))]}
- (set! bpset (λ (loc)
- (let {[addr (bp_init loc)]}
- (when (has? bptbl addr)
- (error "breakpoint already set at " loc))
- (put! bptbl addr (bpsave addr))
- (writecore addr bpinst))))
- (set! bpdel (λ (loc)
- (let {[addr (bp_init loc)]}
- (unless (has? bptbl addr)
- (error "breakpoint not set at " loc))
- (writecore addr (get bptbl addr))
- (del! bptbl addr)))))
+(def (bpset loc)
+ "Set a breakpoint at the location.
-(doc-for (bpset loc)
- «Set a breakpoint.
+ Location is as in loc->addr"
+ :doc-see loc->addr
+ :doc-see bpdel
+ :doc-group lsd
+ (def (txtsymb s) (symbol-addr (global-symbol s :text T)))
+ (waitstop)
+ (let {[addr (loc->addr loc :str->symbol txtsymb)]}
+ (when (has? bptbl addr)
+ (error "breakpoint already set at " loc))
+ (put! bptbl addr (bpsave addr))
+ (core-write addr bpinst)))
- The location can be one of the following:
+(def (bpdel loc)
+ "Delete a breakpoint at the location.
- 1. A sym, in which case the address will be retrieved from
- the global text symbols of the process,
- 2. A num which is the address at which to place the break.
- 3. An LSD symbol in which the case the symbol's address is used.
- 4. A string of the form "file:line" which specifies a line in a
- file of source code.
+ Location is as in loc->addr"
+ :doc-see loc->addr
+ :doc-see bpdel
+ :doc-group lsd
+ (def (txtsymb s) (symbol-addr (global-symbol s :text T)))
+ (waitstop)
+ (let {[addr (loc->addr loc :str->symbol txtsymb)]}
+ (unless (has? bptbl addr)
+ (error "breakpoint not set at " loc))
+ (core-write addr (get bptbl addr))
+ (del! bptbl addr)))
- Examples:
-
- (bpset 'strcpy) ; breakpoint on strcpy function.
- (bpset (curPC)) ; breakpoint on current instruction.
- (bpset "/sys/src/cmd/cat.c:26") ; breakpoint on line 26.»
- :doc-group lsd)
-
-(doc-for (bpdel loc)
- «Delete a breakpoint.
-
- The location can be one of the following:
-
- 1. A sym, in which case the address will be retrieved from
- the global text symbols of the process,
- 2. A num which is the address at which to place the break.
- 3. An LSD symbol in which the case the symbol's address is used.
- 4. A string of the form "file:line" which specifies a line in a
- file of source code.
-
- Examples:
-
- (bpdel 'strcpy) ; remove breakpoint on strcpy function.
- (bpdel (curPC)) ; remove breakpoint on current instruction.
- (bpdel "/sys/src/cmd/cat.c:26") ; remove breakpoint on line 26.»
- :doc-group lsd)
-
(def (detach)
(when regsf (io-close regsf))
(when fpregsf (io-close fpregsf))
@@ -252,20 +249,6 @@
(prog1 (caddr (read-all sf))
(io-close sf))))
-(def tracers (table
- "386" (λ () (lsd-ctrace (curPC) (readreg SP) (u64 0)))
- "68020" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg A7)))
- "amd64" (λ () (lsd-ctrace (curPC) (readreg SP) (u64 0)))
- "arm" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg R14)))
- "arm64" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg R30)))
- "mips" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg R31)))
- "power" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg LR)))
- "power64" (λ () (lsd-ctrace (curPC) (readreg SP) (readreg LR)))))
-
-(def ctrace (get tracers (os-getenv "objtype")))
-
-(def ptrsz (lsd-ptrsize))
-
(def (_stk (:level 0) (:n NIL))
"Return the call stack in the form of a list of stack frames.
Optionally specify what level of the stack to return, starting at
@@ -298,7 +281,7 @@
(princ
(str-join
(map (λ (p)
- (str (symbol-name p) "=" (hex (symbol-read p 'u64))))
+ (str (symbol-name p) "=" (hex (symbol-read p 'u64))))
params)
", "))
(princ ")+" (hex (- pc (symbol-addr fsym))) " ")
@@ -327,7 +310,9 @@
:doc-see stk
(stk :locals T :level level :n n))
-(def (curPC) (and (>= pid 0) (readreg PC)))
+(def (curPC) (if (>= pid 0)
+ (reg-read PC)
+ (error "No active process")))
(def (step (n 1))
"Step `n` assembly instructions. Return the next instruction address
@@ -337,24 +322,29 @@
(curPC)
(let* {[addr (curPC)]
[on-bp (has? bptbl addr)]}
- (when on-bp (writecore addr (get bptbl addr)))
- (let* {[f (follow addr)]
- [o (map bpsave f)]}
- (for-each (λ (a) (writecore a bpinst)) f)
+ (when on-bp (core-write addr (get bptbl addr)))
+ (let* {[fs (follow addr)]
+ [os (map bpsave fs)]}
+ (for-each (λ (f) (core-write f bpinst)) fs)
(startstop)
- (map writecore f o)
- (when on-bp (writecore addr bpinst))
+ (for-each (λ (f o) (core-write f o)) fs os)
+ (when on-bp (core-write addr bpinst))
(step (1- n))))))
(def (cont (:print T))
- "Continue program execution. Return the next instruction address to be
- executed or `NIL` if the program has exited."
+ "Continue program execution.
+
+ Return the next instruction address to be executed or `void` if the
+ program has exited. Optionally print any notes that may have caused
+ the program to stop."
:doc-group lsd
(when (has? bptbl (curPC)) (step))
(let {[note (startstop)]}
(and print (not (void? note)) (princ note "\n")))
- (let {[pc (curPC)]}
- (and print pc (princ (hex pc) "\n"))))
+ (trycatch
+ (let {[pc (curPC)]}
+ (and print pc (princ (hex pc) "\n")))
+ (λ (_) (void))))
(def (func)
"Continue program execution until the current function returns."
@@ -361,15 +351,15 @@
:doc-group lsd
(let* {[bp (frame-retpc (car (_stk)))]
[o (bpsave bp)]}
- (writecore bp bpinst)
+ (core-write bp bpinst)
(cont :print NIL)
- (writecore bp o))
+ (core-write bp o))
(curPC))
(def (line)
"Step one line of the source code.
- This will step into functions not over."
+ Note: This will step into functions not over."
:doc-group lsd
(let {[orig (src)]}
(def (go)
@@ -394,7 +384,7 @@
(curPC)
(func))))
-(def (asmlist (n 5) (addr (readreg PC)))
+(def (asmlist (n 5) (addr (reg-read PC)))
"Return a list of the next `n` disassembled instructions starting at
`addr`. Just like `(asm)` but returns a list instead of printing.
@@ -404,13 +394,13 @@
(if (<= n 0)
()
(let {[on-bp (has? bptbl addr)]}
- (when on-bp (writecore addr (get bptbl addr)))
+ (when on-bp (core-write addr (get bptbl addr)))
(let {[instr (lsd-das addr)]
[isize (lsd-instsize addr)]}
- (when on-bp (writecore addr bpinst))
+ (when on-bp (core-write addr bpinst))
(cons (cons addr instr) (asmlist (1- n) (+ addr isize)))))))
-(def (asm (n 5) (addr (readreg PC)))
+(def (asm (n 5) (addr (reg-read PC)))
"Print the next `n` disassembled instructions at `addr`.
Examples:
@@ -417,7 +407,7 @@
(asm) ; print out 5 from current program instruction.
(asm 10) ; print out 10 from current program instruction.
- (asm 3 (sym-addr 'strecpy)) ; 3 instructions from strecpy"
+ (asm 3 (str->addr "strecpy")) ; 3 instructions from strecpy"
:doc-group lsd
(for-each (λ (i) (princ (hex (car i)) "\t" (cdr i) "\n"))
(asmlist n addr)))
@@ -473,41 +463,38 @@
(unless line (error "bad line number"))
(lsd-file2pc (car s) line)))))
-(def (sym-global s)
- «Return a symbol from the attached proc's symbol table or `NIL`. Input
- is a `sym`.
+(def (global-symbol s (:text NIL) (:data NIL))
+ «Return a symbol from the attached proc's symbol table or `NIL`.
+ Input is a `str`. Optionally specify whether to search only text
+ symbols or data symbols. The default is to search both.
+
Examples:
- (sym-global 'strecpy) → #(symbol "strecpy" #\T 2276784)»
+ (global-symbol "strecpy") → #(symbol "strecpy" #\T 2276784)»
:doc-group lsd
(def (find tbl k) (and (has? tbl k) (get tbl k)))
- (or (find (global-text globals) s)
- (find (global-data globals) s)))
+ (when (and (eq? text NIL) (eq? data NIL))
+ (set! text T)
+ (set! data T))
+ (or (and text (find (global-text globals) s))
+ (and data (find (global-data globals) s))))
-(def (sym-local s (:level 0))
+(def (local-symbol s (:level 0))
«Return a local symbol from the attached proc's current stack frame
- or `NIL`. Input is a `sym`. Optionally specify what level of the
+ or `NIL`. Input is a `str`. Optionally specify what level of the
stack frame to search.
Examples:
- (sym-local 'i) → #(symbol "i" #\a 140737488350940)
- (symbol-read (sym-local 'argc) 's32) → #s32(2)»
+ (local-symbol "i") → #(symbol "i" #\a 140737488350940)
+ (symbol-read (local-symbol "argc") 's32) → #s32(2)»
:doc-group lsd
:doc-see _stk
- (let {[ss (str s)]}
- (find ss
- (frame-locals (car (_stk :level level)))
- :key symbol-name)))
+ (find s
+ (frame-locals (car (_stk :level level)))
+ :key symbol-name))
-(def (sym-addr s (:local NIL))
- "Return the address of a symbol from the attached proc's symbol table
- or NIL. Input is a sym. Optionally specify whether to search the
- local stack frame for the symbol."
- :doc-group lsd
- (symbol-addr ((if local sym-local sym-global) s)))
-
(add-exit-hook
(λ (s)
(when proc-stdin (io-close proc-stdin))
@@ -532,7 +519,7 @@
(set! pid (aref v 0))
(set! proc-stdin (aref v 1))
(attach)
- (map bpset (follow (sym-addr 'main)))
+ (map bpset (follow (symbol-addr (global-symbol "main"))))
(startstop)
pid))
@@ -541,7 +528,7 @@
attach to a process if one is running."
:doc-group lsd
(let* {[v (lsd-load a)]
- [f (λ (symbol tbl) (put! tbl (sym (symbol-name symbol)) symbol))]
+ [f (λ (symbol tbl) (put! tbl (symbol-name symbol) symbol))]
[text (foldl f (table) (aref v 3))]
[data (foldl f (table) (aref v 4))]}
(set! pid (aref v 0))
--
⑨