std.debug — ptrace & Perf-Counter

import std.debug;

Zwei unabhängige Subsysteme in einer Unit:

  • ptrace: Prozess-Debugging und Tracing (Attach, Peek/Poke Adressraum, Register, Single-Step)
  • perf_event_open: Hardware/Software-Performance-Counter (CPU-Cycles, Cache-Misses, Page-Faults)

std.bpf · std.ns · std.security_ext


ptrace — Konstanten

Kommandos

Konstante Wert Beschreibung
PTRACE_TRACEME 0 Kind markiert sich als traceable (vor exec() aufrufen)
PTRACE_PEEKTEXT 1 Wort aus Code-Segment lesen
PTRACE_PEEKDATA 2 Wort aus Daten-Segment lesen
PTRACE_POKETEXT 4 Wort in Code-Segment schreiben
PTRACE_POKEDATA 5 Wort in Daten-Segment schreiben
PTRACE_CONT 7 Tracee weiterlaufen lassen
PTRACE_SINGLESTEP 9 Eine Instruktion ausführen
PTRACE_GETREGS 12 Register lesen (user_regs_struct)
PTRACE_SETREGS 13 Register setzen
PTRACE_ATTACH 16 An laufenden Prozess anheften
PTRACE_DETACH 17 Lostrennen, Tracee läuft weiter
PTRACE_SYSCALL 24 Bei nächstem Syscall stoppen
PTRACE_SETOPTIONS 16896 Optionen setzen
PTRACE_SEIZE 16902 Attach ohne initialen Stop

PTRACE_SETOPTIONS-Flags

Konstante Beschreibung
PTRACE_O_TRACESYSGOOD Syscall-Stops mit bit 7 in Signal markieren
PTRACE_O_TRACEFORK fork()-Ereignisse verfolgen
PTRACE_O_TRACEVFORK vfork()-Ereignisse verfolgen
PTRACE_O_TRACECLONE clone()-Ereignisse verfolgen
PTRACE_O_TRACEEXEC execve()-Ereignisse verfolgen
PTRACE_O_TRACEEXIT exit()-Ereignisse verfolgen

PTRACE_REGS_SIZE: 216 Bytes (27 Register × 8 Bytes für x86-64).


ptrace — Funktionen

Funktion Signatur Beschreibung
PtraceTraceme (): int64 Markiert aktuellen Prozess als debuggable für Elternprozess
PtraceAttach (pid: int64): int64 Heftet sich an laufenden Prozess; sendet SIGSTOP
PtraceDetach (pid: int64, sig: int64): int64 Löst Verbindung; sig=0 sendet kein Signal
PtraceCont (pid: int64, sig: int64): int64 Setzt gestoppten Tracee fort
PtraceSingleStep (pid: int64): int64 Führt genau eine Instruktion im Tracee aus
PtracePeek (pid: int64, addr: int64): int64 Liest 64-Bit-Wort aus Adressraum des Tracee
PtracePoke (pid: int64, addr: int64, val: int64): int64 Schreibt 64-Bit-Wort in Adressraum des Tracee
PtraceGetRegs (pid: int64, regsOut: int64): int64 Liest alle Register in Puffer (PTRACE_REGS_SIZE Bytes)
PtraceSetOptions (pid: int64, opts: int64): int64 Setzt Trace-Optionen (PTRACE_O_*)

perf_event_open — Konstanten

Event-Typen

Konstante Wert Beschreibung
PERF_TYPE_HARDWARE 0 Hardware-Zähler (CPU-spezifisch)
PERF_TYPE_SOFTWARE 1 Kernel-Software-Zähler
PERF_TYPE_TRACEPOINT 2 Kernel-Tracepoint
PERF_TYPE_HW_CACHE 3 Hardware-Cache-Ereignisse
PERF_TYPE_RAW 4 Raw-PMU-Ereigniscode
PERF_TYPE_BREAKPOINT 5 Hardware-Watchpoint/Breakpoint

Hardware-Events (PERF_TYPE_HARDWARE)

Konstante Beschreibung
PERF_COUNT_HW_CPU_CYCLES CPU-Taktzyklen
PERF_COUNT_HW_INSTRUCTIONS Ausgeführte Instruktionen
PERF_COUNT_HW_CACHE_REFERENCES Cache-Zugriffe
PERF_COUNT_HW_CACHE_MISSES Cache-Misses
PERF_COUNT_HW_BRANCH_INSTR Branch-Instruktionen
PERF_COUNT_HW_BRANCH_MISSES Branch-Mispredictions

Software-Events (PERF_TYPE_SOFTWARE)

Konstante Beschreibung
PERF_COUNT_SW_CPU_CLOCK CPU-Zeit in Nanosekunden
PERF_COUNT_SW_TASK_CLOCK Task-Zeit in Nanosekunden
PERF_COUNT_SW_PAGE_FAULTS Alle Page-Faults
PERF_COUNT_SW_CONTEXT_SWITCHES Kontextwechsel
PERF_COUNT_SW_CPU_MIGRATIONS CPU-Migrationen

ioctl-Codes

Konstante Wert Beschreibung
PERF_EVENT_IOC_ENABLE 9216 Counter aktivieren
PERF_EVENT_IOC_DISABLE 9217 Counter deaktivieren
PERF_EVENT_IOC_RESET 9219 Counter auf 0 zurücksetzen

PERF_ATTR_SIZE: 128 Bytes (perf_event_attr-Struktur).


perf_event_open — Funktionen

Funktion Signatur Beschreibung
PerfEventOpen (attr: int64, pid: int64, cpu: int64, groupFd: int64, flags: int64): int64 Öffnet beliebiges Perf-Ereignis; gibt fd zurück
PerfCount (type_: int64, config: int64): int64 Öffnet einfachen Software/Hardware-Counter für aktuellen Prozess
PerfRead (fd: int64): int64 Liest aktuellen Zählerstand (uint64)
PerfEnable (fd: int64): int64 Aktiviert Counter
PerfDisable (fd: int64): int64 Deaktiviert Counter
PerfReset (fd: int64): int64 Setzt Counter auf 0 zurück

Verwendung

Instruktionen einer Funktion zählen

import std.debug;
import std.io;

fn main(): int64 {
    var fd: int64 := PerfCount(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS);
    if (fd < 0) { return fd; }

    PerfEnable(fd);
    // --- zu messender Code ---
    var i: int64 := 0;
    while (i < 1000) { i := i + 1; }
    // -------------------------
    PerfDisable(fd);

    var count: int64 := PerfRead(fd);
    // count = Anzahl ausgeführter Instruktionen im Loop
    close(fd);
    return 0;
}

CPU-Zeit messen

import std.debug;

fn MeasureNs(): int64 {
    var fd: int64 := PerfCount(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK);
    if (fd < 0) { return fd; }

    PerfReset(fd);
    PerfEnable(fd);
    // ... zu messendes Stück ...
    PerfDisable(fd);

    var ns: int64 := PerfRead(fd);
    close(fd);
    return ns;
}

Prozess debuggen (Breakpoint-Grundprinzip)

import std.debug;
import std.alloc;

fn SimpleTrace(pid: int64): int64 {
    var r: int64 := PtraceAttach(pid);
    if (r < 0) { return r; }

    // Adresse aus Adressraum lesen
    var word: int64 := PtracePeek(pid, 0x400000);

    // Register auslesen
    var regs: int64 := alloc(PTRACE_REGS_SIZE);
    PtraceGetRegs(pid, regs);
    // regs+0 = r15, regs+8 = r14, ..., regs+128 = rip (x86-64 user_regs_struct)

    PtraceDetach(pid, 0);
    free(regs, PTRACE_REGS_SIZE);
    return 0;
}


Hinweise

  • Berechtigungen ptrace: PtraceAttach erfordert dass der Ziel-Prozess vom selben User gestartet wurde oder der Caller CAP_SYS_PTRACE hat. YAMA LSM (ptrace_scope=1) schränkt es weiter ein.
  • Berechtigungen perf: PerfCount mit pid=0 (aktueller Prozess) benötigt keine Root-Rechte. pid=-1 (alle Prozesse) erfordert CAP_PERFMON oder root.
  • perf_event_attr: Für komplexe Konfigurationen (Sampling, Gruppen) muss der 128-Byte-Puffer manuell befüllt und PerfEventOpen direkt aufgerufen werden.
  • user_regs_struct x86-64: Offset 128 = rip (Instruction Pointer). Vollständiges Layout in Linux-Kernel-Headern <sys/user.h>.

Letzte Aktualisierung: 2026-06-06