Files
gasm-sdk/debug/disasm_freebsd_amd64.go
T

66 lines
1.9 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
//go:build freebsd && amd64
package debug
import (
"fmt"
"strings"
"sourcedock.dev/petrbalvin/gasm-sdk/arch"
"sourcedock.dev/petrbalvin/gasm-sdk/disasm"
)
// Disassemble decodes the instruction at the given address in the debuggee's
// memory and returns its text representation and length in bytes. An amd64
// instruction is up to 15 bytes long, but the read must not reach past the
// end of the mapping: when the full 15-byte window crosses into unmapped
// memory the window shrinks, because an instruction at the mapping's end is
// by construction no longer than the readable bytes that hold it.
func (s *Session) Disassemble(addr uint64) (string, int, error) {
var lastErr error
for _, n := range []int{15, 8, 4, 2, 1} {
mem, err := s.ReadMemory(addr, n)
if err != nil {
lastErr = err
continue
}
ins, derr := disasm.Decode(arch.AMD64, mem, addr)
if derr != nil {
return "", 0, derr
}
return ins.Text, ins.Len, nil
}
return "", 0, lastErr
}
// DisassembleN decodes up to n instructions starting at addr and returns
// them as a formatted string with addresses and byte offsets.
func (s *Session) DisassembleN(addr uint64, n int) string {
var result strings.Builder
pc := addr
for range n {
text, length, err := s.Disassemble(pc)
if err != nil {
result.WriteString(fmt.Sprintf(" %#08x: <error: %v>\n", pc, err))
break
}
result.WriteString(fmt.Sprintf(" %#08x: %s\n", pc, text))
if length == 0 {
length = 1
}
pc += uint64(length)
}
return result.String()
}
// isCallInsn reports whether disassembled text (x86asm.IntelSyntax) is a
// call. The first token must match exactly: a prefix test would also catch
// unrelated mnemonics.
func isCallInsn(text string) bool {
m, _, _ := strings.Cut(text, " ")
return strings.ToLower(m) == "call"
}