PTRACE(2)
π¦ NAME π¦
ptrace β process tracing and debugging. Yes bestie, this is PTRACE(2), straight out of the System Calls Manual. Buckle up. π
π LIBRARY π
Standard C Library (libc, -lc). The classics.
β¨ SYNOPSIS β¨
#include <sys/types.h>
#include <sys/ptrace.h>
int
ptrace(int request, pid_t pid, caddr_t addr, int data);
π DESCRIPTION π
okay so. The ptrace() system call is the tracing-and-debugging facility. It lets one process (we call her the tracing process) control another one (the traced process). Main character energy, honestly.
The tracing process has to attach first, and then fire off a whole series of ptrace() system calls to control how the process executes, plus peek at its memory and register state. For the entire duration of the tracing session, the traced process gets βre-parentedβ β its parent process ID (and all the behavior that comes with it) gets changed over to the tracing process. And yes, one tracing process is absolutely allowed to attach to more than one other process at the same time. Multi-tasking queen. π
When the tracing process finishes its work, it must detach the traced process.
β οΈ If a tracing process exits without first detaching all the processes it attached to, those processes will be killed. No cap. Not a vibe. Detach your children, bestie.
Most of the time the traced process just runs normally, but the second it receives a signal (see sigaction(2)), it stops. The tracing process is expected to notice that via wait(2) or by getting a SIGCHLD signal, then examine the state of the stopped process and either terminate it or continue it, whichever makes sense. πΈ
That signal could be a totally normal process signal β generated by the traced process's own behavior, or by someone using the kill(2) system call. Or alternatively it could be generated by the tracing facility itself, because of attaching, because the tracing process stepped it, or because of some event in the traced process. The tracing process can choose to intercept the signal and use it to observe process behavior (like SIGTRAP, iconic), or just forward it along to the process if that's the move. The ptrace() system call is the mechanism by which literally all of this happens. π«Ά
A traced process may report additional signal stops corresponding to events in the traced process. These extras get reported as SIGTRAP or SIGSTOP signals. The tracing process can use the PT_LWPINFO request to figure out which events are associated with a SIGTRAP or SIGSTOP signal.
π‘ Note that multiple events may be associated with a single signal. For example, events indicated by thePL_FLAG_BORN,PL_FLAG_FORKED, andPL_FLAG_EXECflags are also reported as a system call exit event (PL_FLAG_SCX).
The signal stop for a new child process enabled via PTRACE_FORK will report a SIGSTOP signal. All other additional signal stops use SIGTRAP.
Every traced process has a tracing event mask. An event in the traced process only reports a signal stop if the corresponding flag is set in the tracing event mask. The current set of tracing event flags includes:
PTRACE_EXECβ report a stop for a successful invocation ofexecve(2). This event is indicated by thePL_FLAG_EXECflag in thepl_flagsmember ofstruct ptrace_lwpinfo.PTRACE_SCEβ report a stop on each system call entry. This event is indicated by thePL_FLAG_SCEflag in thepl_flagsmember ofstruct ptrace_lwpinfo.PTRACE_SCXβ report a stop on each system call exit. This event is indicated by thePL_FLAG_SCXflag in thepl_flagsmember ofstruct ptrace_lwpinfo.PTRACE_SYSCALLβ report stops for both system call entry and exit. Best of both worlds, slay. β¨PTRACE_FORKβ this event flag controls tracing for new child processes of a traced process.
When this event flag is enabled, new child processes will enable tracing and stop before executing their first instruction. The new child process will include the PL_FLAG_CHILD flag in the pl_flags member of struct ptrace_lwpinfo. The traced process will report a stop that includes the PL_FLAG_FORKED flag. The process ID of the new child process will also be present in the pl_child_pid member of struct ptrace_lwpinfo. If the new child process was created via vfork(2), the traced process's stop will also include the PL_FLAG_VFORKED flag. Note that new child processes will be attached with the default tracing event mask β they do not inherit the event mask of the traced process.
When this event flag is not enabled, new child processes will execute without tracing enabled.
PTRACE_LWPβ this event flag controls tracing of LWP (kernel thread) creation and destruction. When this event is enabled, new LWPs will stop and report an event withPL_FLAG_BORNset before executing their first instruction, and exiting LWPs will stop and report an event withPL_FLAG_EXITEDset before completing their termination.
Note that new processes do not report an event for the creation of their initial thread, and exiting processes do not report an event for the termination of the last thread. π
PTRACE_VFORKβ report a stop event when a parent process resumes after avfork(2).
When a thread in the traced process creates a new child process via vfork(2), the stop that reports PL_FLAG_FORKED and PL_FLAG_SCX occurs just after the child process is created, but before the thread waits for the child process to stop sharing process memory. If a debugger is not tracing the new child process, it must ensure that no breakpoints are enabled in the shared process memory before detaching from the new child process. Which means: no breakpoints are enabled in the parent process either. Careful, bestie. π
The PTRACE_VFORK flag enables a new stop that indicates when the new child process stops sharing the process memory of the parent process. A debugger can reinsert breakpoints in the parent process and resume it in response to this event. This event is indicated by setting the PL_FLAG_VFORK_DONE flag.
The default tracing event mask when attaching to a process via PT_ATTACH, PT_TRACE_ME, or PTRACE_FORK includes only PTRACE_EXEC events. All other event flags are disabled. Periodt.
The request argument specifies what operation is being performed. The meaning of the rest of the arguments depends on the operation, but β except for one special case noted below β all ptrace() calls are made by the tracing process, and the pid argument specifies the process ID of the traced process or a corresponding thread ID. π
The request argument can be:
PT_TRACE_MEβ this request is the only one used by the traced process; it declares that the process expects to be traced by its parent. All the other arguments are ignored. (If the parent process doesn't expect to trace the child, it's gonna be, like, rather confused by the results. Once the traced process stops, it cannot be made to continue except viaptrace().) When a process has used this request and callsexecve(2)or any of the routines built on it (such asexecv(3)), it will stop before executing the first instruction of the new image. Also, any setuid or setgid bits on the executable being executed will be ignored. If the child was created by thevfork(2)system call or anrfork(2)call with theRFMEMflag specified, the debugging events are reported to the parent only after theexecve(2)is executed.PT_READ_I,PT_READ_Dβ these requests read a singleintof data from the traced process's address space. Traditionally,ptrace()has allowed for machines with distinct address spaces for instruction and data, which is why there are two requests: conceptually,PT_READ_Ireads from the instruction space andPT_READ_Dreads from the data space. In the current FreeBSD implementation, these two requests are completely identical. Theaddrargument specifies the address (in the traced process's virtual address space) at which the read is to be done. This address does not have to meet any alignment constraints. The value read is returned as the return value fromptrace(). πPT_WRITE_I,PT_WRITE_Dβ these requests parallelPT_READ_IandPT_READ_D, except that they write rather than read. Thedataargument supplies the value to be written.PT_IOβ this request allows reading and writing arbitrary amounts of data in the traced process's address space. Theaddrargument specifies a pointer to astruct ptrace_io_desc, which is defined as follows:
struct ptrace_io_desc {
int piod_op; /* I/O operation */
void *piod_offs; /* child offset */
void *piod_addr; /* parent offset */
size_t piod_len; /* request length */
};
/*
* Operations in piod_op.
*/
#define PIOD_READ_D 1 /* Read from D space */
#define PIOD_WRITE_D 2 /* Write to D space */
#define PIOD_READ_I 3 /* Read from I space */
#define PIOD_WRITE_I 4 /* Write to I space */
The data argument is ignored. The actual number of bytes read or written is stored in piod_len upon return. π«
π PT_CONTINUE β the "go bestie, keep going" request
Your traced process keeps executing, periodt. The addr argument is an address that says where execution should resume β literally a whole new value for the program counter, main character energy. Or you pass (caddr_t)1 to say "nah, just pick up exactly where it left off, we're not doing anything fancy." The data argument hands over a signal number to be delivered to the traced process as it resumes, or 0 if you're not sending any signal at all. β¨
π¦ PT_STEP β one instruction at a time, babes
The traced process gets single stepped, one (1) instruction, and that's it. The addr argument should be passed (caddr_t)1. The data argument provides a signal number to be delivered to the traced process as it resumes execution, or 0 if no signal is to be sent. Tiny steps, huge slay. π
π PT_KILL β the dramatic exit
The traced process terminates, exactly as if PT_CONTINUE had been used with SIGKILL given as the signal to be delivered. It's giving "we're so done here." Not a soft launch, not a gentle goodbye β it's SIGKILL, iykyk. π
π PT_ATTACH β walking up to a stranger and saying "you're mine now"
This request lets a process gain control of an otherwise unrelated process and begin tracing it. Zero cooperation required from the to-be-traced process β it doesn't even have to know, which is lowkey unhinged but that's the assignment. π
In this case, pid specifies the process ID of the to-be-traced process, and the other two arguments are just ignored, like they're not even there.
Okay but there are rules, bestie. This request requires that the target process must have the same real UID as the tracing process, and that it must not be executing asetuidorsetgidexecutable. (If the tracing process is running as root, these restrictions do not apply β root stays iconic and unbothered. π)
The tracing process will see the newly-traced process stop, and may then control it as if it had been traced all along. Instant adoption. π«Ά
πΈ PT_DETACH β the "you're free now, go live your life" request
This request is like PT_CONTINUE, except that it does not allow specifying an alternate place to continue execution. And after it succeeds, the traced process is no longer traced and just continues execution normally. No strings, no lingering situationship. π¦
β PT_GETREGS β reading the machine registers
This request reads the traced process's machine registers into the βstruct regβ (defined in <machine/reg.h>) pointed to by addr. Get you a struct that can hold all that. π
π PT_SETREGS β writing them back
This request is the converse of PT_GETREGS; it loads the traced process's machine registers from the βstruct regβ (defined in <machine/reg.h>) pointed to by addr. Symmetry, we love to see it. β¨
π PT_GETFPREGS β floating-point registers, but make it read
This request reads the traced process's floating-point registers into the βstruct fpregβ (defined in <machine/reg.h>) pointed to by addr.
π§ PT_SETFPREGS β floating-point registers, but make it write
This request is the converse of PT_GETFPREGS; it loads the traced process's floating-point registers from the βstruct fpregβ (defined in <machine/reg.h>) pointed to by addr.
π₯ PT_GETDBREGS β debug registers, incoming
This request reads the traced process's debug registers into the βstruct dbregβ (defined in <machine/reg.h>) pointed to by addr.
π PT_SETDBREGS β debug registers, outgoing
This request is the converse of PT_GETDBREGS; it loads the traced process's debug registers from the βstruct dbregβ (defined in <machine/reg.h>) pointed to by addr.
π PT_LWPINFO β the "who exactly stopped me" request
This request can be used to obtain information about the kernel thread, also known as a lightweight process, that caused the traced process to stop. The addr argument specifies a pointer to a struct ptrace_lwpinfo, which is defined as follows:
struct ptrace_lwpinfo {
lwpid_t pl_lwpid;
int pl_event;
int pl_flags;
sigset_t pl_sigmask;
sigset_t pl_siglist;
siginfo_t pl_siginfo;
char pl_tdname[MAXCOMLEN + 1];
pid_t pl_child_pid;
u_int pl_syscall_code;
u_int pl_syscall_narg;
};
The data argument is to be set to the size of the structure known to the caller. That way the structure can grow later without affecting older programs β future-proofing, we stan. π
okay so the fields in struct ptrace_lwpinfo are giving major lore, and here's exactly what each one means π
pl_lwpidβ the LWP id of the threadpl_eventβ the event that caused the stop. The currently defined events are:PL_EVENT_NONEβ no reason given, she's just mysterious like thatPL_EVENT_SIGNALβ the thread stopped because of the pending signal
pl_flagsβ flags that spill the extra tea about the stop you're looking at. The currently defined ones are:PL_FLAG_SCEβ the thread stopped on a system call entry, right after the kernel got entered. The debugger is allowed to peek at the syscall arguments chilling in memory and registers, per the ABI of the current process, and even modify them if it needs to. main character debugger behavior frPL_FLAG_SCXβ the thread is stopped right before the syscall returns to usermode. The debugger can inspect the system call return values sitting in the ABI-defined registers and/or memory.PL_FLAG_EXECβ whenPL_FLAG_SCXis set, this flag can be set as well, to let you know the program being executed by the debuggee process got changed because a system call from theexecve(2)family ran successfully. glow-up via exec, iconicPL_FLAG_SIβ tells you that thepl_siginfomember ofstruct ptrace_lwpinfois holding valid informationPL_FLAG_FORKEDβ the process is returning from a call tofork(2)that created a new child process. The process identifier of that new process is available in thepl_child_pidmember ofstruct ptrace_lwpinfo. baby's first process πΌPL_FLAG_CHILDβ set for the first event reported from a new child, which gets automatically attached whenPTRACE_FORKis enabledPL_FLAG_BORNβ set for the first event reported from a new LWP whenPTRACE_LWPis enabled. It gets reported right along withPL_FLAG_SCX.PL_FLAG_EXITEDβ set for the last event reported by an exiting LWP whenPTRACE_LWPis enabled. Heads up though: this event is not reported when the last LWP in a process exits. The termination of that final thread comes through as a normal process exit event instead. no grand finale for the last one πPL_FLAG_VFORKEDβ the thread is returning from a call tovfork(2)that created a new child process. This one is set in addition toPL_FLAG_FORKED.PL_FLAG_VFORK_DONEβ the thread has resumed after a child process created viavfork(2)stopped sharing its address space with the traced process.
pl_sigmaskβ the current signal mask of the LWPpl_siglistβ the current pending set of signals for the LWP. Watch out bestie: signals that get delivered to the process will not appear on an LWP siglist until the thread is actually selected for delivery. patience is a virtue πpl_siginfoβ thesiginfothat comes with the pending signal. Only valid for aPL_EVENT_SIGNALstop whenPL_FLAG_SIis set inpl_flags.pl_tdnameβ the name of the threadpl_child_pidβ the process identifier of the new child process. Only valid for aPL_EVENT_SIGNALstop whenPL_FLAG_FORKEDis set inpl_flags.pl_syscall_codeβ the ABI-specific identifier of the current system call. Note that for indirect system calls this field reports the indirected system call. Only valid whenPL_FLAG_SCEorPL_FLAG_SCXis set inpl_flags.pl_syscall_nargβ the number of arguments passed to the current system call, not counting the system call identifier. Note that for indirect system calls this field reports the arguments passed to the indirected system call. Only valid whenPL_FLAG_SCEorPL_FLAG_SCXis set inpl_flags.
and now, the requests themselves β the whole lineup, no skips β¨
PT_GETNUMLWPSβ this request returns the number of kernel threads associated with the traced process.PT_GETLWPLISTβ this one grabs the current thread list for you. Pass a pointer to an array of typelwpid_tinaddr, with the array size specified bydata. The return value fromptrace()is the count of array entries that got filled in.PT_SETSTEPβ turns on single stepping for the specified process. Stepping gets automatically disabled when a single step trap is caught.PT_CLEARSTEPβ turns off single stepping for the specified process.PT_SUSPENDβ suspends the specified thread. nap time π¦PT_RESUMEβ resumes the specified thread. wake up queen πPT_TO_SCEβ sets thePTRACE_SCEevent flag so you trace all future system call entries, then continues the process. Theaddranddataarguments are used the same as forPT_CONTINUE.PT_TO_SCXβ sets thePTRACE_SCXevent flag so you trace all future system call exits, then continues the process. Theaddranddataarguments are used the same as forPT_CONTINUE.PT_SYSCALLβ sets thePTRACE_SYSCALLevent flag so you trace all future system call entries and exits, then continues the process. Theaddranddataarguments are used the same as forPT_CONTINUE.PT_GET_SC_ARGSβ for a thread stopped in either thePL_FLAG_SCEorPL_FLAG_SCXstate (so, on entry or exit to a syscall), this request fetches the syscall arguments.
The arguments get copied out into the buffer pointed to by the addr pointer, sequentially. Each syscall argument is stored as the machine word. The kernel copies out as many arguments as the syscall accepts β see the pl_syscall_narg member of the struct ptrace_lwpinfo β but no more than data bytes in total get copied.
PT_GET_SC_RETβ fetches the system call return values on exit from a syscall. This request is only valid for threads stopped in a syscall exit (thePL_FLAG_SCXstate). Theaddrargument specifies a pointer to astruct ptrace_sc_ret, which is defined like this:
struct ptrace_sc_ret {
register_t sr_retval[2];
int sr_error;
};
The data argument gets set to the size of the structure.
If the system call completed successfully, sr_error is set to zero and the return values of the system call are saved in sr_retval. If the system call failed to execute, the sr_error field is set to a positive errno(2) value. If the system call completed in an unusual fashion, sr_error is set to a negative value:
ERESTARTβ bestie, the syscall is gonna get restarted. like it said "hold on, be right back" πEJUSTRETURNβ the syscall finished successfully but did not set a return value (thinksetcontext(2)andsigreturn(2), the iconics that just vibe on through).PT_FOLLOW_FORKβ this one controls tracing for new child processes of a traced process, no cap. Ifdatais non-zero,PTRACE_FORKgets set in the traced process's event tracing mask. Ifdatais zero,PTRACE_FORKgets cleared from the traced process's event tracing mask. set it, clear it, it's giving toggle energy β¨PT_LWP_EVENTSβ same vibe but for LWP (lightweight process) creation and destruction. Ifdatais non-zero,PTRACE_LWPis set in the traced process's event tracing mask. Ifdatais zero,PTRACE_LWPis cleared from the traced process's event tracing mask. π¦PT_GET_EVENT_MASKβ reads the traced process's event tracing mask into the integer thataddrpoints at. the size of that integer has to be passed indata. don't forget it, she's mandatory πPT_SET_EVENT_MASKβ sets the traced process's event tracing mask from the integer thataddrpoints at. the size of the integer goes indata. same deal πPT_VM_TIMESTAMPβ returns the generation number (aka the timestamp) of the traced process's memory map, handed back as the return value fromptrace(). it's the low-cost way for the tracing process to figure out if the VM map changed since the last time it made this request. cheap and effective, main character behavior πPT_VM_ENTRYβ this request iterates over the entries of the VM map of the traced process. theaddrargument is a pointer to astruct ptrace_vm_entry, which is defined as follows:
struct ptrace_vm_entry {
int pve_entry;
int pve_timestamp;
u_long pve_start;
u_long pve_end;
u_long pve_offset;
u_int pve_prot;
u_int pve_pathlen;
long pve_fileid;
uint32_t pve_fsid;
char *pve_path;
};
The first entry comes back when you set pve_entry to zero. Subsequent entries come back when you leave pve_entry unmodified from the value that previous requests returned β so like, don't touch it, she remembers where she was π«Ά
The pve_timestamp field is there to detect changes to the VM map while you're iterating over the entries. The tracing process can then take appropriate action, such as restarting. By setting pve_pathlen to a non-zero value on entry, the pathname of the backing object is returned in the buffer pointed to by pve_path, provided the entry is backed by a vnode. The pve_pathlen field is updated with the actual length of the pathname (including the terminating null character). The pve_offset field is the offset within the backing object at which the range starts. The range is located in the VM space at pve_start and extends up to pve_end (inclusive).
The data argument is ignored. literally ignored. not even looked at π
π ARM MACHINE-SPECIFIC REQUESTS π
PT_GETVFPREGSβ return the thread's VFP machine state in the buffer pointed to byaddr.
The data argument is ignored.
PT_SETVFPREGSβ set the thread's VFP machine state from the buffer pointed to byaddr.
The data argument is ignored.
π x86 MACHINE-SPECIFIC REQUESTS π
PT_GETXMMREGSβ copy the XMM FPU state into the buffer pointed to by the argumentaddr. The buffer has the same layout as the 32-bit save buffer for the machine instructionFXSAVE.
This request is only valid for i386 programs, both on native 32-bit systems and on amd64 kernels. For 64-bit amd64 programs, the XMM state is reported as part of the FPU state returned by the PT_GETFPREGS request.
The data argument is ignored.
PT_SETXMMREGSβ load the XMM FPU state for the thread from the buffer pointed to by the argumentaddr. The buffer has the same layout as the 32-bit load buffer for the machine instructionFXRSTOR.
As with PT_GETXMMREGS, this request is only valid for i386 programs.
The data argument is ignored.
PT_GETXSTATE_INFOβ report which XSAVE FPU extensions are supported by the CPU and allowed in userspace programs. Theaddrargument must point to a variable of typestruct ptrace_xstate_info, which contains the information on the request return.struct ptrace_xstate_infois defined as follows:
struct ptrace_xstate_info {
uint64_t xsave_mask;
uint32_t xsave_len;
};
The xsave_mask field is a bitmask of the currently enabled extensions. The meaning of the bits is defined in the Intel and AMD processor documentation. The xsave_len field reports the length of the XSAVE area for storing the hardware state for currently enabled extensions in the format defined by the x86 XSAVE machine instruction.
The data argument value must be equal to the size of the struct ptrace_xstate_info. no wiggle room, she's strict π
PT_GETXSTATEβ return the content of the XSAVE area for the thread. Theaddrargument points to the buffer where the content is copied, and thedataargument specifies the size of the buffer. The kernel copies out as much content as allowed by the buffer size. The buffer layout is specified by the layout of the save area for the XSAVE machine instruction.PT_SETXSTATEβ load the XSAVE state for the thread from the buffer specified by theaddrpointer. The buffer size is passed in thedataargument. The buffer must be at least as large as thestruct savefpu(defined inx86/fpu.h) to allow the complete x87 FPU and XMM state load. It must not be larger than the XSAVE state length, as reported by thexsave_lenfield from thestruct ptrace_xstate_infoof thePT_GETXSTATE_INFOrequest. Layout of the buffer is identical to the layout of the load area for theXRSTORmachine instruction.
not me stressing the size bounds but fr fr, too small and too big are both a no π
PT_GETFSBASEβ return the value of the base used when doing segmented memory addressing using the%fssegment register. Theaddrargument points to anunsigned longvariable where the base value is stored.
The data argument is ignored.
PT_GETGSBASEβ like thePT_GETFSBASErequest, but returns the base for the%gssegment register.PT_SETFSBASEβ set the base for the%fssegment register to the value pointed to by theaddrargument.addrmust point to theunsigned longvariable containing the new base.
The data argument is ignored.
PT_SETGSBASEβ like thePT_SETFSBASErequest, but sets the base for the%gssegment register.
π PowerPC MACHINE-SPECIFIC REQUESTS π
PT_GETVRREGSβ return the thread's ALTIVEC machine state in the buffer pointed to byaddr.
The data argument is ignored.
PT_SETVRREGSβ set the thread's ALTIVEC machine state from the buffer pointed to byaddr.
The data argument is ignored.
PT_GETVSRREGSβ return doubleword 1 of the thread's VSX registersVSR0-VSR31in the buffer pointed to byaddr.
The data argument is ignored.
PT_SETVSRREGSβ set doubleword 1 of the thread's VSX registersVSR0-VSR31from the buffer pointed to byaddr.
The data argument is ignored.
Additionally, other machine-specific requests can exist. so like, stay curious bestie π¦
β¨ RETURN VALUES β¨
Most requests return 0 on success and -1 on error. But β and this is the plot twist β some requests can cause ptrace() to return -1 as a non-error value. Among them are PT_READ_I and PT_READ_D, which return the value read from the process memory on success. π
To disambiguate, set errno to 0 before the call and check it afterwards. it's the classic "was that a real error or just the vibe" check π
The current ptrace() implementation always sets errno to 0 before calling into the kernel, both for historic reasons and for consistency with other operating systems. It is recommended to assign zero to errno explicitly for forward compatibility. yes, explicitly. do it anyway, future-proof yourself π«Ά
π ERRORS π
bestie. listen. ptrace() can flop, and here's exactly how it flops. every single one of these is real and you will meet them all eventually. The ptrace() system call may fail if:
[ESRCH]β the process said "who?" and meant it:- No process having the specified process ID exists. ghosted fr fr π»
[EINVAL]β you gave it something it simply cannot work with:- A process attempted to use
PT_ATTACHon itself. not the self-attach π bestie you cannot trace yourself, that's giving main character syndrome - The request argument was not one of the legal requests. made-up request? jail. π
- The signal number (in data) to
PT_CONTINUEwas neither0nor a legal signal number. PT_GETREGS,PT_SETREGS,PT_GETFPREGS,PT_SETFPREGS,PT_GETDBREGS, orPT_SETDBREGSwas attempted on a process with no valid register set. (This is normally true only of system processes.) system processes stay unregistered, it's their whole vibePT_VM_ENTRYwas given an invalid value forpve_entry. This can also be caused by changes to the VM map of the process. the map moved while you were looking at it, iconic chaos- The size (in data) provided to
PT_LWPINFOwas less than or equal to zero, or larger than theptrace_lwpinfostructure known to the kernel. - The size (in data) provided to the x86-specific
PT_GETXSTATE_INFOrequest was not equal to the size of thestruct ptrace_xstate_info. exact match only, she's picky π - The size (in data) provided to the x86-specific
PT_SETXSTATErequest was less than the size of the x87 plus the XMM save area. - The size (in data) provided to the x86-specific
PT_SETXSTATErequest was larger than returned in thexsave_lenmember of thestruct ptrace_xstate_infofrom thePT_GETXSTATE_INFOrequest. - The base value, provided to the amd64-specific requests
PT_SETFSBASEorPT_SETGSBASE, pointed outside of the valid user address space. This error will not occur in 32-bit programs. 32-bit girlies, this one's not for you π«Ά
- A process attempted to use
[EBUSY]β she's booked, occupied, not available, do not perceive her:PT_ATTACHwas attempted on a process that was already being traced. somebody already got there first, sorry babe- A request attempted to manipulate a process that was being traced by some process other than the one making the request.
- A request (other than
PT_ATTACH) specified a process that was not stopped. it has to be STOPPED. paused. frozen. periodt.
[EPERM]β permission? never heard of her:- A request (other than
PT_ATTACH) attempted to manipulate a process that was not being traced at all. there's no trace to speak of, bestie, it's giving nothing - An attempt was made to use
PT_ATTACHon a process in violation of the requirements listed underPT_ATTACHabove. scroll back up, the rules are right there π₯
- A request (other than
[ENOENT]β you asked for one more and there isn't one:PT_VM_ENTRYpreviously returned the last entry of the memory map. No more entries exist. you ate the whole map. it's empty. go home. π½οΈ
[ENAMETOOLONG]β the name did not fit in the lil outfit you gave it:PT_VM_ENTRYcannot return the pathname of the backing object because the buffer is not big enough.pve_pathlenholds the minimum buffer size required on return. she's literally telling you the size you need, take the hint π
π SEE ALSO π
the besties you should also be reading, no cap:
execve(2)sigaction(2)wait(2)execv(3)i386_clr_watch(3)i386_set_watch(3)
π¦ HISTORY π¦
The ptrace() function appeared in Version 6 AT&T UNIX. she's been doing this since the actual 1970s, absolute legend, the blueprint, the original icon π
okay that's the whole page bestie, you made it, I'm so proud of you π«Άπ this whole saga lives in the Debian ptrace(2) manual, dated July 15, 2019 β go forth and trace responsibly, mwah π
β¨πΈ
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms