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:
PtraceAttacherfordert dass der Ziel-Prozess vom selben User gestartet wurde oder der CallerCAP_SYS_PTRACEhat.YAMA LSM(ptrace_scope=1) schränkt es weiter ein. - Berechtigungen perf:
PerfCountmitpid=0(aktueller Prozess) benötigt keine Root-Rechte.pid=-1(alle Prozesse) erfordertCAP_PERFMONoder root. - perf_event_attr: Für komplexe Konfigurationen (Sampling, Gruppen) muss der 128-Byte-Puffer manuell befüllt und
PerfEventOpendirekt 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
