2026-08-20 23:57:10 +02:00
|
|
|
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
|
|
//go:build linux
|
|
|
|
|
|
|
|
|
|
package debug
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"syscall"
|
|
|
|
|
"unsafe"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// mapRWX maps code into a read-write-execute region.
|
|
|
|
|
func mapRWX(code []byte) ([]byte, error) {
|
|
|
|
|
const pageSize = 4096
|
|
|
|
|
size := (len(code) + pageSize - 1) &^ (pageSize - 1)
|
|
|
|
|
mem, err := syscall.Mmap(-1, 0, size,
|
|
|
|
|
syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC,
|
|
|
|
|
syscall.MAP_PRIVATE|syscall.MAP_ANON)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
copy(mem, code)
|
|
|
|
|
return mem, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setupBuffers allocates buffers in the debuggee's memory.
|
|
|
|
|
func setupBuffers(spec string, args []byte, argSize int, tmpDir string) ([]byte, error) {
|
|
|
|
|
type bufSpec struct {
|
|
|
|
|
name string
|
|
|
|
|
size int
|
|
|
|
|
pattern string
|
|
|
|
|
}
|
|
|
|
|
var specs []bufSpec
|
2026-08-29 15:40:31 +02:00
|
|
|
for part := range strings.SplitSeq(spec, ",") {
|
2026-08-20 23:57:10 +02:00
|
|
|
fields := strings.SplitN(part, ":", 3)
|
|
|
|
|
if len(fields) != 3 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
size, err := strconv.Atoi(fields[1])
|
|
|
|
|
if err != nil || size <= 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
specs = append(specs, bufSpec{name: fields[0], size: size, pattern: fields[2]})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(specs) == 0 {
|
|
|
|
|
return args, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var bufAddrs []uint64
|
|
|
|
|
for _, s := range specs {
|
|
|
|
|
buf, err := syscall.Mmap(-1, 0, s.size,
|
|
|
|
|
syscall.PROT_READ|syscall.PROT_WRITE,
|
|
|
|
|
syscall.MAP_PRIVATE|syscall.MAP_ANON)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("mmap buffer %s: %w", s.name, err)
|
|
|
|
|
}
|
|
|
|
|
fillBuffer(buf, s.pattern)
|
|
|
|
|
bufAddrs = append(bufAddrs, uint64(uintptr(unsafe.Pointer(&buf[0]))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addrFile, err := os.Create(tmpDir + "/bufaddrs")
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
for _, addr := range bufAddrs {
|
|
|
|
|
fmt.Fprintf(addrFile, "%d\n", addr)
|
|
|
|
|
}
|
|
|
|
|
addrFile.Close()
|
|
|
|
|
|
|
|
|
|
return args, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fillBuffer fills a buffer with the specified pattern.
|
|
|
|
|
func fillBuffer(buf []byte, pattern string) {
|
|
|
|
|
switch pattern {
|
|
|
|
|
case "zero":
|
|
|
|
|
case "ones":
|
|
|
|
|
for i := range buf {
|
|
|
|
|
buf[i] = 0xFF
|
|
|
|
|
}
|
|
|
|
|
case "seq":
|
|
|
|
|
for i := range buf {
|
|
|
|
|
buf[i] = byte(i)
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
if data, err := hex.DecodeString(pattern); err == nil && len(data) > 0 {
|
|
|
|
|
for i := range buf {
|
|
|
|
|
buf[i] = data[i%len(data)]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|