Skip to content

Commit 9df5287

Browse files
committed
Syscall wrappers for ptrace and supporting wait-related flags.
R=rsc APPROVED=rsc DELTA=311 (308 added, 3 deleted, 0 changed) OCL=31569 CL=31606
1 parent e48d8fe commit 9df5287

File tree

4 files changed

+308
-3
lines changed

4 files changed

+308
-3
lines changed

src/pkg/syscall/syscall_linux.go

+158
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,163 @@ func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
386386
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l));
387387
}
388388

389+
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
390+
391+
// See bytes.Copy.
392+
func bytesCopy(dst, src []byte) int {
393+
if len(src) > len(dst) {
394+
src = src[0:len(dst)];
395+
}
396+
for i, x := range src {
397+
dst[i] = x
398+
}
399+
return len(src)
400+
}
401+
402+
func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
403+
// The peek requests are machine-size oriented, so we wrap it
404+
// to retrieve arbitrary-length data.
405+
406+
// The ptrace syscall differs from glibc's ptrace.
407+
// Peeks returns the word in *data, not as the return value.
408+
409+
var buf [sizeofPtr]byte;
410+
411+
// Leading edge. PEEKTEXT/PEEKDATA don't require aligned
412+
// access (PEEKUSER warns that it might), but if we don't
413+
// align our reads, we might straddle an unmapped page
414+
// boundary and not get the bytes leading up to the page
415+
// boundary.
416+
n := 0;
417+
if addr % sizeofPtr != 0 {
418+
errno = ptrace(req, pid, addr - addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])));
419+
if errno != 0 {
420+
return 0, errno;
421+
}
422+
n += bytesCopy(out, buf[addr%sizeofPtr:len(buf)]);
423+
out = out[n:len(out)];
424+
}
425+
426+
// Remainder.
427+
for len(out) > 0 {
428+
// We use an internal buffer to gaurantee alignment.
429+
// It's not documented if this is necessary, but we're paranoid.
430+
errno = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])));
431+
if errno != 0 {
432+
return n, errno;
433+
}
434+
copied := bytesCopy(out, &buf);
435+
n += copied;
436+
out = out[copied:len(out)];
437+
}
438+
439+
return n, 0;
440+
}
441+
442+
func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
443+
return ptracePeek(_PTRACE_PEEKTEXT, pid, addr, out);
444+
}
445+
446+
func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
447+
return ptracePeek(_PTRACE_PEEKDATA, pid, addr, out);
448+
}
449+
450+
func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
451+
// As for ptracePeek, we need to align our accesses to deal
452+
// with the possibility of straddling an invalid page.
453+
454+
// Leading edge.
455+
n := 0;
456+
if addr % sizeofPtr != 0 {
457+
var buf [sizeofPtr]byte;
458+
errno = ptrace(peekReq, pid, addr - addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])));
459+
if errno != 0 {
460+
return 0, errno;
461+
}
462+
n += bytesCopy(buf[addr%sizeofPtr:len(buf)], data);
463+
word := *((*uintptr)(unsafe.Pointer(&buf[0])));
464+
errno = ptrace(pokeReq, pid, addr - addr%sizeofPtr, word);
465+
if errno != 0 {
466+
return 0, errno;
467+
}
468+
data = data[n:len(data)];
469+
}
470+
471+
// Interior.
472+
for len(data) > sizeofPtr {
473+
word := *((*uintptr)(unsafe.Pointer(&data[0])));
474+
errno = ptrace(pokeReq, pid, addr+uintptr(n), word);
475+
if errno != 0 {
476+
return n, errno;
477+
}
478+
n += sizeofPtr;
479+
data = data[sizeofPtr:len(data)];
480+
}
481+
482+
// Trailing edge.
483+
if len(data) > 0 {
484+
var buf [sizeofPtr]byte;
485+
errno = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])));
486+
if errno != 0 {
487+
return n, errno;
488+
}
489+
bytesCopy(&buf, data);
490+
word := *((*uintptr)(unsafe.Pointer(&buf[0])));
491+
errno = ptrace(pokeReq, pid, addr+uintptr(n), word);
492+
if errno != 0 {
493+
return n, errno;
494+
}
495+
n += len(data);
496+
}
497+
498+
return n, 0;
499+
}
500+
501+
func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
502+
return ptracePoke(_PTRACE_POKETEXT, _PTRACE_PEEKTEXT, pid, addr, data);
503+
}
504+
505+
func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
506+
return ptracePoke(_PTRACE_POKEDATA, _PTRACE_PEEKDATA, pid, addr, data);
507+
}
508+
509+
func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
510+
return ptrace(_PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)));
511+
}
512+
513+
func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
514+
return ptrace(_PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)));
515+
}
516+
517+
func PtraceSetOptions(pid int, options int) (errno int) {
518+
return ptrace(_PTRACE_SETOPTIONS, pid, 0, uintptr(options));
519+
}
520+
521+
func PtraceGetEventMsg(pid int) (msg uint, errno int) {
522+
var data _C_long;
523+
errno = ptrace(_PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)));
524+
if errno != 0 {
525+
msg = uint(data);
526+
}
527+
return;
528+
}
529+
530+
func PtraceCont(pid int, signal int) (errno int) {
531+
return ptrace(_PTRACE_CONT, pid, 0, uintptr(signal));
532+
}
533+
534+
func PtraceSingleStep(pid int) (errno int) {
535+
return ptrace(_PTRACE_SINGLESTEP, pid, 0, 0);
536+
}
537+
538+
func PtraceAttach(pid int) (errno int) {
539+
return ptrace(_PTRACE_ATTACH, pid, 0, 0);
540+
}
541+
542+
func PtraceDetach(pid int) (errno int) {
543+
return ptrace(_PTRACE_DETACH, pid, 0, 0);
544+
}
545+
389546
// Sendto
390547
// Recvfrom
391548
// Sendmsg
@@ -634,3 +791,4 @@ func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
634791
// Waitid
635792
// Writev
636793
// _Sysctl
794+

src/pkg/syscall/types_linux.c

+66-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Input to godefs. See PORT.
1313

1414
#include <dirent.h>
1515
#include <fcntl.h>
16+
#include <linux/user.h>
1617
#include <netinet/in.h>
1718
#include <netinet/tcp.h>
1819
#include <signal.h>
@@ -52,6 +53,12 @@ enum
5253
$PathMax = PATH_MAX,
5354
};
5455

56+
// Basic types
57+
58+
typedef short $_C_short;
59+
typedef int $_C_int;
60+
typedef long $_C_long;
61+
typedef long long $_C_long_long;
5562

5663
// Time
5764

@@ -67,7 +74,6 @@ typedef struct utimbuf $Utimbuf;
6774
typedef struct rusage $Rusage;
6875
typedef struct rlimit $Rlimit;
6976

70-
typedef int $_C_int;
7177
typedef gid_t $_Gid_t;
7278

7379
// Files
@@ -130,6 +136,11 @@ enum
130136
$WSTOPPED = WSTOPPED,
131137
$WCONTINUED = WCONTINUED,
132138
$WNOWAIT = WNOWAIT,
139+
140+
// Linux-specific
141+
$WCLONE = __WCLONE,
142+
$WALL = __WALL,
143+
$WNOTHREAD = __WNOTHREAD,
133144
};
134145

135146
// Sockets
@@ -192,6 +203,60 @@ typedef struct sockaddr_any $RawSockaddrAny;
192203
typedef socklen_t $_Socklen;
193204
typedef struct linger $Linger;
194205

206+
// Ptrace
207+
208+
// Ptrace requests
209+
enum {
210+
$_PTRACE_TRACEME = PTRACE_TRACEME,
211+
$_PTRACE_PEEKTEXT = PTRACE_PEEKTEXT,
212+
$_PTRACE_PEEKDATA = PTRACE_PEEKDATA,
213+
$_PTRACE_PEEKUSER = PTRACE_PEEKUSER,
214+
$_PTRACE_POKETEXT = PTRACE_POKETEXT,
215+
$_PTRACE_POKEDATA = PTRACE_POKEDATA,
216+
$_PTRACE_POKEUSER = PTRACE_POKEUSER,
217+
$_PTRACE_CONT = PTRACE_CONT,
218+
$_PTRACE_KILL = PTRACE_KILL,
219+
$_PTRACE_SINGLESTEP = PTRACE_SINGLESTEP,
220+
$_PTRACE_GETREGS = PTRACE_GETREGS,
221+
$_PTRACE_SETREGS = PTRACE_SETREGS,
222+
$_PTRACE_GETFPREGS = PTRACE_GETFPREGS,
223+
$_PTRACE_SETFPREGS = PTRACE_SETFPREGS,
224+
$_PTRACE_ATTACH = PTRACE_ATTACH,
225+
$_PTRACE_DETACH = PTRACE_DETACH,
226+
$_PTRACE_GETFPXREGS = PTRACE_GETFPXREGS,
227+
$_PTRACE_SETFPXREGS = PTRACE_SETFPXREGS,
228+
$_PTRACE_SYSCALL = PTRACE_SYSCALL,
229+
$_PTRACE_SETOPTIONS = PTRACE_SETOPTIONS,
230+
$_PTRACE_GETEVENTMSG = PTRACE_GETEVENTMSG,
231+
$_PTRACE_GETSIGINFO = PTRACE_GETSIGINFO,
232+
$_PTRACE_SETSIGINFO = PTRACE_SETSIGINFO,
233+
};
234+
235+
// PTRACE_SETOPTIONS options
236+
enum {
237+
$PTRACE_O_TRACESYSGOOD = PTRACE_O_TRACESYSGOOD,
238+
$PTRACE_O_TRACEFORK = PTRACE_O_TRACEFORK,
239+
$PTRACE_O_TRACEVFORK = PTRACE_O_TRACEVFORK,
240+
$PTRACE_O_TRACECLONE = PTRACE_O_TRACECLONE,
241+
$PTRACE_O_TRACEEXEC = PTRACE_O_TRACEEXEC,
242+
$PTRACE_O_TRACEVFORKDONE = PTRACE_O_TRACEVFORKDONE,
243+
$PTRACE_O_TRACEEXIT = PTRACE_O_TRACEEXIT,
244+
$PTRACE_O_MASK = PTRACE_O_MASK,
245+
};
246+
247+
// Extended result codes
248+
enum {
249+
$PTRACE_EVENT_FORK = PTRACE_EVENT_FORK,
250+
$PTRACE_EVENT_VFORK = PTRACE_EVENT_VFORK,
251+
$PTRACE_EVENT_CLONE = PTRACE_EVENT_CLONE,
252+
$PTRACE_EVENT_EXEC = PTRACE_EVENT_EXEC,
253+
$PTRACE_EVENT_VFORK_DONE = PTRACE_EVENT_VFORK_DONE,
254+
$PTRACE_EVENT_EXIT = PTRACE_EVENT_EXIT,
255+
};
256+
257+
// Register structures
258+
typedef struct user_regs_struct $PtraceRegs;
259+
195260
// Misc
196261

197262
enum {

src/pkg/syscall/zsyscall_linux_amd64.go

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
4242
return;
4343
}
4444

45+
func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
46+
r0, r1, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0);
47+
errno = int(e1);
48+
return;
49+
}
50+
4551
func Access(path string, mode int) (errno int) {
4652
r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0);
4753
errno = int(e1);

src/pkg/syscall/ztypes_linux_amd64.go

+78-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ const (
4949
WSTOPPED = 0x2;
5050
WCONTINUED = 0x8;
5151
WNOWAIT = 0x1000000;
52+
WCLONE = 0x80000000;
53+
WALL = 0x40000000;
54+
WNOTHREAD = 0x20000000;
5255
AF_UNIX = 0x1;
5356
AF_INET = 0x2;
5457
AF_INET6 = 0xa;
@@ -74,6 +77,43 @@ const (
7477
SizeofSockaddrInet6 = 0x1c;
7578
SizeofSockaddrAny = 0x1c;
7679
SizeofSockaddrUnix = 0x6e;
80+
_PTRACE_TRACEME = 0;
81+
_PTRACE_PEEKTEXT = 0x1;
82+
_PTRACE_PEEKDATA = 0x2;
83+
_PTRACE_PEEKUSER = 0x3;
84+
_PTRACE_POKETEXT = 0x4;
85+
_PTRACE_POKEDATA = 0x5;
86+
_PTRACE_POKEUSER = 0x6;
87+
_PTRACE_CONT = 0x7;
88+
_PTRACE_KILL = 0x8;
89+
_PTRACE_SINGLESTEP = 0x9;
90+
_PTRACE_GETREGS = 0xc;
91+
_PTRACE_SETREGS = 0xd;
92+
_PTRACE_GETFPREGS = 0xe;
93+
_PTRACE_SETFPREGS = 0xf;
94+
_PTRACE_ATTACH = 0x10;
95+
_PTRACE_DETACH = 0x11;
96+
_PTRACE_GETFPXREGS = 0x12;
97+
_PTRACE_SETFPXREGS = 0x13;
98+
_PTRACE_SYSCALL = 0x18;
99+
_PTRACE_SETOPTIONS = 0x4200;
100+
_PTRACE_GETEVENTMSG = 0x4201;
101+
_PTRACE_GETSIGINFO = 0x4202;
102+
_PTRACE_SETSIGINFO = 0x4203;
103+
PTRACE_O_TRACESYSGOOD = 0x1;
104+
PTRACE_O_TRACEFORK = 0x2;
105+
PTRACE_O_TRACEVFORK = 0x4;
106+
PTRACE_O_TRACECLONE = 0x8;
107+
PTRACE_O_TRACEEXEC = 0x10;
108+
PTRACE_O_TRACEVFORKDONE = 0x20;
109+
PTRACE_O_TRACEEXIT = 0x40;
110+
PTRACE_O_MASK = 0x7f;
111+
PTRACE_EVENT_FORK = 0x1;
112+
PTRACE_EVENT_VFORK = 0x2;
113+
PTRACE_EVENT_CLONE = 0x3;
114+
PTRACE_EVENT_EXEC = 0x4;
115+
PTRACE_EVENT_VFORK_DONE = 0x5;
116+
PTRACE_EVENT_EXIT = 0x6;
77117
EPOLLIN = 0x1;
78118
EPOLLRDHUP = 0x2000;
79119
EPOLLOUT = 0x4;
@@ -85,6 +125,14 @@ const (
85125

86126
// Types
87127

128+
type _C_short int16
129+
130+
type _C_int int32
131+
132+
type _C_long int64
133+
134+
type _C_long_long int64
135+
88136
type Timespec struct {
89137
Sec int64;
90138
Nsec int64;
@@ -170,8 +218,6 @@ type Rlimit struct {
170218
Max uint64;
171219
}
172220

173-
type _C_int int32
174-
175221
type _Gid_t uint32
176222

177223
type Stat_t struct {
@@ -252,6 +298,36 @@ type Linger struct {
252298
Linger int32;
253299
}
254300

301+
type PtraceRegs struct {
302+
R15 uint64;
303+
R14 uint64;
304+
R13 uint64;
305+
R12 uint64;
306+
Rbp uint64;
307+
Rbx uint64;
308+
R11 uint64;
309+
R10 uint64;
310+
R9 uint64;
311+
R8 uint64;
312+
Rax uint64;
313+
Rcx uint64;
314+
Rdx uint64;
315+
Rsi uint64;
316+
Rdi uint64;
317+
Orig_rax uint64;
318+
Rip uint64;
319+
Cs uint64;
320+
Eflags uint64;
321+
Rsp uint64;
322+
Ss uint64;
323+
Fs_base uint64;
324+
Gs_base uint64;
325+
Ds uint64;
326+
Es uint64;
327+
Fs uint64;
328+
Gs uint64;
329+
}
330+
255331
type FdSet struct {
256332
Bits [16]int64;
257333
}

0 commit comments

Comments
 (0)