====== 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