feat(debug): complete the interactive debugger with disassembly, breakpoints, watchpoints and execution control
Assisted-by: DeepSeek V4 Pro
This commit is contained in:
+8
-6
@@ -23,7 +23,7 @@ import (
|
||||
// operands require relocations and are not yet supported; the SIMD (VEX/AVX2)
|
||||
// integer and shuffle/extract/permute/move set is in.
|
||||
func Assemble(t *ast.Text) ([]byte, map[string]int, error) {
|
||||
code, _, labels, _, err := assemble(t, nil)
|
||||
code, _, labels, _, _, err := assemble(t, nil)
|
||||
return code, labels, err
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ type spadjStep struct {
|
||||
// assemble encodes a TEXT body, returning the machine code, the static-symbol
|
||||
// patch sites (for the file-level layout to resolve), the label table and the
|
||||
// stack-adjustment boundaries.
|
||||
func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, []spadjStep, error) {
|
||||
func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, []spadjStep, []LineEntry, error) {
|
||||
fi := computeFrame(t)
|
||||
chain := jumpChain(t)
|
||||
resolve := func(name string) string {
|
||||
@@ -84,7 +84,7 @@ func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, [
|
||||
case *ast.Instr:
|
||||
sz, err := instrSize(s, fi, long[i], link)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("%s: %w", s.Mnemonic.Text, err)
|
||||
return nil, nil, nil, nil, nil, fmt.Errorf("%s: %w", s.Mnemonic.Text, err)
|
||||
}
|
||||
sizes[i] = sz
|
||||
pcs[i] = pos
|
||||
@@ -125,6 +125,7 @@ func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, [
|
||||
out := append([]byte(nil), fi.prologue...)
|
||||
var patches []sbPatch
|
||||
var steps []spadjStep
|
||||
var lines []LineEntry
|
||||
if fi.useFP {
|
||||
// PUSHQ BP saves the return-address-relative base (+8); the MOVQ
|
||||
// changes nothing; SUBQ $size, SP completes the frame.
|
||||
@@ -150,16 +151,17 @@ func assemble(t *ast.Text, link *linkInfo) ([]byte, []sbPatch, map[string]int, [
|
||||
}
|
||||
code, ps, err := encodeInstr(s, pos, offsets, fi, long[i], resolve, link)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("%s: %w", s.Mnemonic.Text, err)
|
||||
return nil, nil, nil, nil, nil, fmt.Errorf("%s: %w", s.Mnemonic.Text, err)
|
||||
}
|
||||
if len(code) != sizes[i] {
|
||||
return nil, nil, nil, nil, fmt.Errorf("%s: size mismatch (%d vs %d)", s.Mnemonic.Text, len(code), sizes[i])
|
||||
return nil, nil, nil, nil, nil, fmt.Errorf("%s: size mismatch (%d vs %d)", s.Mnemonic.Text, len(code), sizes[i])
|
||||
}
|
||||
patches = append(patches, ps...)
|
||||
lines = append(lines, LineEntry{Offset: pos, Line: s.Pos().Line})
|
||||
out = append(out, code...)
|
||||
pos += len(code)
|
||||
}
|
||||
return out, patches, offsets, steps, nil
|
||||
return out, patches, offsets, steps, lines, nil
|
||||
}
|
||||
|
||||
// jumpChain precomputes jump-to-jump folding: a label whose first instruction
|
||||
|
||||
+32
-1
@@ -41,6 +41,7 @@ type FuncLayout struct {
|
||||
Labels map[string]int // local labels, function-relative
|
||||
Relocs []Reloc // static-symbol references, in emission order
|
||||
Spadj []SpadjStep // stack-adjustment boundaries, ascending by PC
|
||||
Lines []LineEntry // source-line table: byte offset → source line
|
||||
}
|
||||
|
||||
// SpadjStep is one stack-adjustment boundary: Value is the SP delta from the
|
||||
@@ -50,6 +51,35 @@ type SpadjStep struct {
|
||||
Value int
|
||||
}
|
||||
|
||||
// LineEntry maps a byte offset (function-relative) to a source line number.
|
||||
type LineEntry struct {
|
||||
Offset int
|
||||
Line int
|
||||
}
|
||||
|
||||
// LineAt returns the source line number for the given function-relative byte
|
||||
// offset, using a binary search on the line table. Returns 0 if the offset
|
||||
// is before the first instruction or the table is empty.
|
||||
func (fl *FuncLayout) LineAt(offset int) int {
|
||||
if len(fl.Lines) == 0 {
|
||||
return 0
|
||||
}
|
||||
// Binary search: find the last entry with Offset <= offset.
|
||||
lo, hi := 0, len(fl.Lines)-1
|
||||
for lo < hi {
|
||||
mid := (lo + hi + 1) / 2
|
||||
if fl.Lines[mid].Offset <= offset {
|
||||
lo = mid
|
||||
} else {
|
||||
hi = mid - 1
|
||||
}
|
||||
}
|
||||
if fl.Lines[lo].Offset <= offset {
|
||||
return fl.Lines[lo].Line
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Reloc is one static-symbol reference within a function body: the disp32
|
||||
// field at Off (function-relative) must reach the symbol plus Addend,
|
||||
// measured from After, the address just past the instruction. An External
|
||||
@@ -110,7 +140,7 @@ func AssembleFile(f *ast.File) (*Image, error) {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
code, patches, labels, steps, err := assemble(t, link)
|
||||
code, patches, labels, steps, lines, err := assemble(t, link)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", t.Name.Name, err)
|
||||
}
|
||||
@@ -124,6 +154,7 @@ func AssembleFile(f *ast.File) (*Image, error) {
|
||||
Args: argsSize(t),
|
||||
Line: t.Pos().Line,
|
||||
Labels: labels,
|
||||
Lines: lines,
|
||||
}
|
||||
for _, f := range t.Flags {
|
||||
switch f {
|
||||
|
||||
Reference in New Issue
Block a user