====== 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)
→ [[lyx_-_programmiersprache:units:bpf|std.bpf]] · [[lyx_-_programmiersprache:units:ns|std.ns]] · [[lyx_-_programmiersprache:units:security_ext|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 ''''.
----
Letzte Aktualisierung: 2026-06-06