Skip to content

Commit

Permalink
windows: Implements locate_libR_globals() for Windows.
Browse files Browse the repository at this point in the history
Part of #3.
  • Loading branch information
atheriel committed Apr 14, 2020
1 parent 453aa6e commit 913bf38
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 3 deletions.
135 changes: 133 additions & 2 deletions src/locate.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdio.h> /* for fprintf */
#include "locate.h"
#include "memory.h"

#ifdef __linux
#include <fcntl.h> /* for open */
Expand All @@ -11,8 +12,6 @@
#include <libelf.h>
#include <gelf.h>

#include "memory.h"

#define MAX_LIBR_PATH_LEN 128

static int find_libR(pid_t pid, char **path, uintptr_t *addr) {
Expand Down Expand Up @@ -178,6 +177,138 @@ int locate_libR_globals(phandle pid, struct libR_globals *out) {

return 0;
}
#elif defined(__WIN32)
#include <windows.h>
#include <psapi.h> /* for EnumProcessModules */
#include <dbghelp.h> /* for SymInitialize, SymLoadModuleEx, etc */

int locate_libR_globals(phandle pid, struct libR_globals *out) {
/* TODO: Should we use TRUE here to force loading symbols from all modules? */
if (!SymInitialize(pid, NULL, FALSE)) {
fprintf(stderr, "error: Failed to load remote process symbols: %ld.\n",
GetLastError());
return -1;
}

HMODULE mods[1024];
DWORD mod_bytes;
if (!EnumProcessModules(pid, mods, sizeof(mods), &mod_bytes)) {
fprintf(stderr, "error: Failed to enumerate remote process modules: %ld.\n",
GetLastError());
goto error;
}
int entries = mod_bytes / sizeof(HMODULE);

TCHAR mpath[256];
DWORD64 base;
for (int i = 0; i < entries; i++ ) {
if (!GetModuleFileNameEx(pid, mods[i], mpath, sizeof(mpath) / sizeof(TCHAR))) {
fprintf(stderr, "error: Failed to get remote process module: %ld.\n",
GetLastError());
goto error;
}

/* FIXME: Only select the module that looks like R. */

base = SymLoadModuleEx(pid, NULL, mpath, NULL, (DWORD64) mods[i], 0, NULL, 0);
if (!base) {
fprintf(stderr, "error: Failed to load symbols for %s (0x%p): %ld.\n",
mpath, mods[i], GetLastError());
goto error;
}

uintptr_t value;
size_t bytes;
/* This is actually the crazy structure SymFromName uses. */
struct {
SYMBOL_INFO info;
char buf[MAX_SYM_NAME];
} info;
info.info.SizeOfStruct = sizeof(SYMBOL_INFO);
info.info.ModBase = base;
info.info.MaxNameLen = MAX_SYM_NAME - 1;
char *sym;

sym = "R_GlobalContext";
if (!SymFromName(pid, sym, &info.info)) {
if (GetLastError() != 123) {
fprintf(stderr, "error: Failed to lookup symbol: %ld.\n", GetLastError());
goto error;
}
} else {
out->context_addr = info.info.Address;
}

sym = "R_DoubleColonSymbol";
if (!SymFromName(pid, sym, &info.info)) {
if (GetLastError() != 123) {
fprintf(stderr, "error: Failed to lookup symbol: %ld.\n", GetLastError());
goto error;
}
} else {
/* copy_address() will print its own errors. */
bytes = copy_address(pid, (void *) info.info.Address, &value,
sizeof(uintptr_t));
out->doublecolon = bytes < sizeof(uintptr_t) ? 0 : value;
}

sym = "R_TripleColonSymbol";
if (!SymFromName(pid, sym, &info.info)) {
if (GetLastError() != 123) {
fprintf(stderr, "error: Failed to lookup symbol: %ld.\n", GetLastError());
goto error;
}
} else {
bytes = copy_address(pid, (void *) info.info.Address, &value,
sizeof(uintptr_t));
out->triplecolon = bytes < sizeof(uintptr_t) ? 0 : value;
}

sym = "R_DollarSymbol";
if (!SymFromName(pid, sym, &info.info)) {
if (GetLastError() != 123) {
fprintf(stderr, "error: Failed to lookup symbol: %ld.\n", GetLastError());
goto error;
}
} else {
bytes = copy_address(pid, (void *) info.info.Address, &value,
sizeof(uintptr_t));
out->dollar = bytes < sizeof(uintptr_t) ? 0 : value;
}

sym = "R_BracketSymbol";
if (!SymFromName(pid, sym, &info.info)) {
if (GetLastError() != 123) {
fprintf(stderr, "error: Failed to lookup symbol: %ld.\n", GetLastError());
goto error;
}
} else {
bytes = copy_address(pid, (void *) info.info.Address, &value,
sizeof(uintptr_t));
out->bracket = bytes < sizeof(uintptr_t) ? 0 : value;
}

if (!SymUnloadModule64(pid, base)) {
fprintf(stderr, "error: Failed to unload symbols for %s (0x%p): %ld.\n",
mpath, mods[i], GetLastError());
goto error;
}
}

if (!out->doublecolon || !out->triplecolon || !out->dollar || !out->bracket ||
!out->context_addr) {
fprintf(stderr, "error: Failed to locate required R global variables in \
remote process's memory. Are you sure it is an R program?\n");
goto error;
}

SymCleanup(pid);
return 0;

error:
SymCleanup(pid);
return -1;
}
#else
#error "No support for non-Linux platforms."
#endif
3 changes: 2 additions & 1 deletion src/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ LONG NtResumeProcess(IN HANDLE ProcessHandle);

int proc_create(phandle *out, void *data) {
pid_t pid = *((pid_t *) data);
*out = OpenProcess(PROCESS_VM_READ | PROCESS_SUSPEND_RESUME, FALSE, pid);
*out = OpenProcess(PROCESS_VM_READ | PROCESS_SUSPEND_RESUME |
PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!*out) {
fprintf(stderr, "error: Failed to open process %I64d: %ld.\n", pid,
GetLastError());
Expand Down

0 comments on commit 913bf38

Please sign in to comment.