Skip to content

Commit

Permalink
Refactor pid_t-related functionality into a new process handle API.
Browse files Browse the repository at this point in the history
Processes are not pid_t on Windows, so we need a new type for them, and
since it is possible for them to have "state", we might as well create
an new internal API for these "process handles".

Handles are now used when reading memory, when looking up R's symbols,
and when doing system-specific things like "suspending the process".

This should make these APIs possible to implement for Windows (#3).
  • Loading branch information
atheriel committed Apr 14, 2020
1 parent fc854cc commit d00a923
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 57 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ BIN = xrprof
BINOBJ = src/xrprof.o
OBJ = src/cursor.o \
src/locate.o \
src/memory.o
src/memory.o \
src/process.o
SHLIB = libxrprof.so

all: $(BIN)
Expand All @@ -31,6 +32,9 @@ src/locate.o: src/locate.c src/locate.h src/memory.h
src/memory.o: src/memory.c src/memory.h src/rdefs.h
$(CC) $(CFLAGS) -c -o $@ $<

src/process.o: src/process.c
$(CC) $(CFLAGS) -c -o $@ $<

src/xrprof.o: src/xrprof.c src/cursor.h
$(CC) $(CFLAGS) -c -o $@ $<

Expand Down
4 changes: 2 additions & 2 deletions src/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ struct xrprof_cursor {
void *rcxt_ptr;
RCNTXT *cptr;
struct libR_globals globals;
pid_t pid;
phandle pid;
int depth;
};

struct xrprof_cursor *xrprof_create(pid_t pid) {
struct xrprof_cursor *xrprof_create(phandle pid) {
/* Find the symbols and addresses we need. */
struct libR_globals globals;
if (locate_libR_globals(pid, &globals) < 0) return NULL;
Expand Down
4 changes: 2 additions & 2 deletions src/cursor.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#ifndef XRPROF_CURSOR_H
#define XRPROF_CURSOR_H

#include <unistd.h> /* for pid_t */
#include "process.h"

struct xrprof_cursor;

struct xrprof_cursor *xrprof_create(pid_t pid);
struct xrprof_cursor *xrprof_create(phandle pid);
void xrprof_destroy(struct xrprof_cursor *cursor);
int xrprof_init(struct xrprof_cursor *cursor);

Expand Down
2 changes: 1 addition & 1 deletion src/locate.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ static int find_libR(pid_t pid, char **path, uintptr_t *addr) {
}


int locate_libR_globals(pid_t pid, struct libR_globals *out) {
int locate_libR_globals(phandle pid, struct libR_globals *out) {
/* Open the same libR.so in the tracer so we can determine the symbol offsets
to read memory at in the tracee. */

Expand Down
4 changes: 2 additions & 2 deletions src/locate.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define XRPROF_LOCATE_H

#include <stdint.h> /* for uintptr_t */
#include <unistd.h> /* for pid_t */
#include "process.h"

struct libR_globals {
uintptr_t context_addr;
Expand All @@ -12,6 +12,6 @@ struct libR_globals {
uintptr_t bracket;
};

int locate_libR_globals(pid_t pid, struct libR_globals *out);
int locate_libR_globals(phandle pid, struct libR_globals *out);

#endif /* XRPROF_LOCATE_H */
24 changes: 18 additions & 6 deletions src/memory.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
#ifdef __linux
#define _GNU_SOURCE /* for process_vm_readv */
#endif

#include <stdio.h> /* for fprintf, perror, stderr */

#include "memory.h"
#include "rdefs.h"

#ifdef __linux
#include <sys/uio.h> /* for iovec, process_vm_readv */

size_t copy_address(pid_t pid, void *addr, void *data, size_t len) {
/* No-op on Linux. */
int phandle_init(phandle *out, void *data) {
pid_t pid = *((pid_t *) data);
*out = pid;
return 0;
}

size_t copy_address(phandle pid, void *addr, void *data, size_t len) {
struct iovec local[1];
local[0].iov_base = data;
local[0].iov_len = len;
Expand All @@ -24,9 +38,7 @@ size_t copy_address(pid_t pid, void *addr, void *data, size_t len) {
#error "No support for non-Linux platforms."
#endif

#include "rdefs.h"

int copy_context(pid_t pid, void *addr, RCNTXT *data) {
int copy_context(phandle pid, void *addr, RCNTXT *data) {
if (!addr) {
return -1;
}
Expand All @@ -40,7 +52,7 @@ int copy_context(pid_t pid, void *addr, RCNTXT *data) {
return 0;
}

int copy_sexp(pid_t pid, void *addr, SEXP data) {
int copy_sexp(phandle pid, void *addr, SEXP data) {
if (!addr) {
return -1;
}
Expand All @@ -54,7 +66,7 @@ int copy_sexp(pid_t pid, void *addr, SEXP data) {
return 0;
}

int copy_char(pid_t pid, void *addr, char *data, size_t max_len) {
int copy_char(phandle pid, void *addr, char *data, size_t max_len) {
if (!addr) {
return -1;
}
Expand Down
10 changes: 5 additions & 5 deletions src/memory.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#ifndef XRPROF_MEMORY_H
#define XRPROF_MEMORY_H

#include <unistd.h> /* for pid_t */
#include "process.h" /* for phandle */
#include "rdefs.h" /* for RCNTXT, SEXP */

size_t copy_address(pid_t pid, void *addr, void *data, size_t len);
int copy_context(pid_t pid, void *addr, RCNTXT *data);
int copy_sexp(pid_t pid, void *addr, SEXP data);
int copy_char(pid_t pid, void *addr, char *data, size_t max_len);
size_t copy_address(phandle pid, void *addr, void *data, size_t len);
int copy_context(phandle pid, void *addr, RCNTXT *data);
int copy_sexp(phandle pid, void *addr, SEXP data);
int copy_char(phandle pid, void *addr, char *data, size_t max_len);

#endif /* XRPROF_MEMORY_H */
66 changes: 66 additions & 0 deletions src/process.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <stdio.h> /* for fprintf */

#include "process.h"

#ifdef __linux
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>

int proc_create(phandle *out, void *data) {
pid_t *pid = (pid_t *) data;
*out = *pid;
if (ptrace(PTRACE_SEIZE, *out, NULL, NULL)) {
perror("fatal: Failed to attach to remote process");
return -1;
}
return 0;
}

int proc_suspend(phandle pid) {
if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
perror("fatal: Failed to interrupt remote process");
return -1;
}

int wstatus;
if (waitpid(pid, &wstatus, 0) < 0) {
perror("fatal: Failed to obtain remote process status information");
return -1;
}
if (WIFEXITED(wstatus)) {
fprintf(stderr, "Process %d finished.\n", pid);
return -2;
} else if (WIFSTOPPED(wstatus) && WSTOPSIG(wstatus) == SIGCHLD) {
/* Try again. */
ptrace(PTRACE_CONT, pid, NULL, NULL);
return proc_suspend(pid);
} else if (WIFSTOPPED(wstatus) && WSTOPSIG(wstatus) != SIGTRAP) {
fprintf(stderr, "fatal: Unexpected stop signal in remote process: %d.\n",
WSTOPSIG(wstatus));
return -1;
} else if (!WIFSTOPPED(wstatus)) {
fprintf(stderr, "fatal: Unexpected remote process status: %d.\n",
WSTOPSIG(wstatus));
return -1;
}

return 0;
}

int proc_resume(phandle pid) {
if (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
perror("fatal: Failed to continue remote process");
return -1;
}
return 0;
}

int proc_destroy(phandle pid) {
/* We don't actually care if this succeeds or not. */
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return 0;
}
#else
#error "No support for non-Linux platforms."
#endif
16 changes: 16 additions & 0 deletions src/process.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef XRPROF_PROCESS_H
#define XRPROF_PROCESS_H

#ifdef __unix
#include <unistd.h> /* for pid_t */
typedef pid_t phandle;
#else
#error "No support for this platform."
#endif

int proc_create(phandle *out, void *data);
int proc_suspend(phandle pid);
int proc_resume(phandle pid);
int proc_destroy(phandle pid);

#endif /* XRPROF_PROCESS_H */
53 changes: 15 additions & 38 deletions src/xrprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
#include <stdint.h> /* for uintptr_t */
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h> /* for timespec */

#ifdef __linux
Expand All @@ -17,6 +14,7 @@
#endif

#include "cursor.h"
#include "process.h"

#define MAX_STACK_DEPTH 100
#define DEFAULT_FREQ 1
Expand Down Expand Up @@ -127,16 +125,16 @@ int main(int argc, char **argv) {
sleep_spec.tv_sec = freq == 1 ? 1 : 0;
sleep_spec.tv_nsec = freq == 1 ? 0 : 1000000000 / freq;

phandle proc;
int code = 0;

/* First, check that we can attach to the process. */

if (ptrace(PTRACE_SEIZE, pid, NULL, NULL)) {
perror("fatal: Failed to attach to remote process");
return 1;
if ((code = proc_create(&proc, (void *) &pid)) < 0) {
return -code;
}

struct xrprof_cursor *cursor = xrprof_create(pid);
struct xrprof_cursor *cursor = xrprof_create(proc);
if (!cursor) {
fprintf(stderr, "fatal: Failed to initialize R stack cursor.\n");
code++;
Expand All @@ -150,7 +148,7 @@ int main(int argc, char **argv) {
if (mixed_mode) {
uw_as = unw_create_addr_space(&_UPT_accessors, 0);
unw_set_caching_policy(uw_as, UNW_CACHE_GLOBAL);
uw_cxt = _UPT_create(pid);
uw_cxt = _UPT_create(proc);
}
#endif

Expand All @@ -167,32 +165,12 @@ int main(int argc, char **argv) {
printf("sample.interval=%d\n", 1000000 / freq);

while (should_trace && elapsed <= duration) {
if (ptrace(PTRACE_INTERRUPT, pid, NULL, NULL)) {
perror("fatal: Failed to interrupt remote process");
code++;
goto done;
}
int wstatus;
if (waitpid(pid, &wstatus, 0) < 0) {
perror("fatal: Failed to obtain remote process status information");
code++;
goto done;
}
if (WIFEXITED(wstatus)) {
fprintf(stderr, "Process %d finished.\n", pid);
break;
} else if (WIFSTOPPED(wstatus) && WSTOPSIG(wstatus) == SIGCHLD) {
ptrace(PTRACE_CONT, pid, NULL, NULL);
continue;
} else if (WIFSTOPPED(wstatus) && WSTOPSIG(wstatus) != SIGTRAP) {
fprintf(stderr, "fatal: Unexpected stop signal in remote process: %d.\n",
WSTOPSIG(wstatus));
code++;
goto done;
} else if (!WIFSTOPPED(wstatus)) {
fprintf(stderr, "fatal: Unexpected remote process status: %d.\n",
WSTOPSIG(wstatus));
code++;
if ((code = proc_suspend(proc)) < 0) {
if (code == -2) {
code = 0;
break;
}
code = -code;
goto done;
}

Expand Down Expand Up @@ -295,9 +273,8 @@ int main(int argc, char **argv) {
}
printf("\n");

if (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
perror("fatal: Failed to continue remote process");
code++;
if ((code = proc_resume(proc)) < 0) {
code = -code;
goto done;
}
if (nanosleep(&sleep_spec, NULL) < 0) {
Expand All @@ -307,7 +284,7 @@ int main(int argc, char **argv) {
}

done:
ptrace(PTRACE_DETACH, pid, NULL, NULL);
proc_destroy(proc);
xrprof_destroy(cursor);

return code;
Expand Down

0 comments on commit d00a923

Please sign in to comment.