Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Windows #146

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
phpspy
*~
\#*\#
.\#*
.\#*
out
.vs
22 changes: 22 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
cmake_minimum_required (VERSION 3.11)

project ("phpspy")

set(CMAKE_C_STANDARD 11)

include_directories(${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/vendor)
add_definitions(-DPHPSPY_WIN32)

# pcre2
include(FetchContent)
FetchContent_Declare(
pcre
GIT_REPOSITORY https://github.com/PCRE2Project/pcre2.git
GIT_TAG 6ae58beca071f13ccfed31d03b3f479ab520639b #pcre2-10.44
GIT_SUBMODULES ""
)
FetchContent_MakeAvailable(pcre)

add_executable(phpspy basic.c phpspy.c pgrep.c addr_objdump.c event_fout.c event_callgrind.c vendor/getopt.c)

target_link_libraries(phpspy pcre2-posix)
73 changes: 73 additions & 0 deletions addr_objdump.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#include "phpspy.h"
#include <assert.h>

#ifndef PHPSPY_WIN32
static int get_php_bin_path(pid_t pid, char *path_root, char *path);
static int get_php_base_addr(pid_t pid, char *path_root, char *path, uint64_t *raddr);
#else
static int get_php_info(pid_t pid, char *php_bin_path, char *php_dll_path, uint64_t *raddr);
#endif
static int get_symbol_offset(char *path_root, const char *symbol, uint64_t *raddr);
static int popen_read_line(char *buf, size_t buf_size, char *cmd_fmt, ...);

Expand Down Expand Up @@ -58,17 +62,28 @@ int get_symbol_addr(addr_memo_t *memo, pid_t pid, const char *symbol, uint64_t *
php_bin_path = memo->php_bin_path;
php_bin_path_root = memo->php_bin_path_root;
php_base_addr = &memo->php_base_addr;
#ifndef PHPSPY_WIN32
if (*php_bin_path == '\0' && get_php_bin_path(pid, php_bin_path_root, php_bin_path) != 0) {
return 1;
} else if (*php_base_addr == 0 && get_php_base_addr(pid, php_bin_path_root, php_bin_path, php_base_addr) != 0) {
return 1;
} else if (get_symbol_offset(php_bin_path_root, symbol, &addr_offset) != 0) {
return 1;
}
#else
char *php_dll_path = memo->php_dll_path;
if (*php_bin_path == '\0' && get_php_info(pid, php_bin_path, php_dll_path, php_base_addr) != 0) {
return 1;
} else if (get_symbol_offset(php_dll_path, symbol, &addr_offset) != 0) {
return 1;
}
#endif
*raddr = *php_base_addr + addr_offset;
return 0;
}

#ifndef PHPSPY_WIN32

static int get_php_bin_path(pid_t pid, char *path_root, char *path) {
char buf[PHPSPY_STR_SIZE];
char libname[PHPSPY_STR_SIZE];
Expand Down Expand Up @@ -143,6 +158,64 @@ static int get_symbol_offset(char *path_root, const char *symbol, uint64_t *radd
return 0;
}

#else

static int get_php_info(pid_t pid, char *php_bin_path, char *php_dll_path, uint64_t *raddr) {
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;

hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
if (hModuleSnap == INVALID_HANDLE_VALUE) {
log_error("CreateToolhelp32Snapshot (of modules) failed. Error: %lu \n", GetLastError());
return 1;
}

me32.dwSize = sizeof(MODULEENTRY32);

if (!Module32First(hModuleSnap, &me32)) {
printf("Module32First failed. Error: %lu \n", GetLastError());
CloseHandle(hModuleSnap); // Clean the snapshot object.
return 1;
}

do {
if (strncmp(me32.szModule, "php", 3) == 0 && strncmp(me32.szModule + 4, ".dll", 4) == 0) {
strncpy(php_dll_path, me32.szExePath, PHPSPY_STR_SIZE - 1);
*raddr = (uint64_t) me32.modBaseAddr;
} else if (strncmp(me32.szModule, "php.exe", 7) == 0 || strncmp(me32.szModule, "php-cgi.exe", 11) == 0) {
char *last_slash = strrchr(me32.szExePath, '\\');
*last_slash = '\0';
strncpy_s(php_bin_path, PHPSPY_STR_SIZE, me32.szExePath, sizeof(me32.szExePath) - 1);
strncat(php_bin_path, "\\php.exe", 8);
}
} while (Module32Next(hModuleSnap, &me32));

CloseHandle(hModuleSnap);

return 0;
}

static int get_symbol_offset(char *path_root, const char *symbol, uint64_t *raddr) {
char buf[PHPSPY_STR_SIZE];
char arg_buf[PHPSPY_STR_SIZE];
char hex_string[PHPSPY_STR_SIZE];
char *cmd_fmt = "dumpbin /exports %s | findstr %s";

if (popen_read_line(buf, sizeof(buf), cmd_fmt, path_root, symbol) != 0) {
log_error("get_symbol_offset: Failed\n");
return 1;
}
if (sscanf_s(buf, "%*s %*s %s", hex_string, sizeof(hex_string)) == -1) {
log_error("get_symbol_offset: sscanf_s Failed\n");
return 1;
}
*raddr = strtoull(hex_string, NULL, 16);
return 0;
}


#endif

static int popen_read_line(char *buf, size_t buf_size, char *cmd_fmt, ...) {
FILE *fp;
char cmd[PHPSPY_STR_SIZE];
Expand Down
67 changes: 67 additions & 0 deletions basic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <basic.h>
#ifdef PHPSPY_WIN32

void nanosleep(struct timespec *ts, void *null) {
long ns = (ts->tv_sec * 1000000000UL) + (ts->tv_nsec * 1UL);
Sleep(ns / 1000000L);
}

int asprintf(char **ret, char *fmt, ...) {
va_list arg;
int rv;

va_start(arg, fmt);
rv = vsnprintf(NULL, 0, fmt, arg);
if (rv >= 0 && (*ret = malloc(rv + 1))) {
vsnprintf(*ret, rv + 1, fmt, arg);
}
else {
rv = rv < 0 ? rv : -1;
}
va_end(arg);

return rv;
}

int gettimeofday(struct timeval *p, void *z)
{
union {
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
FILETIME ft;
} _now;

if (p) {
GetSystemTimeAsFileTime(&_now.ft);
_now.ns100 -= 116444736000000000ull;
_now.ns100 /= 10;
p->tv_sec = _now.ns100 / 1000000ul;
p->tv_usec = (long)(_now.ns100 % 1000000ul);
}

return 0;
}

int phpspy_thread_create(phpspy_thread_t *thread, phpspy_thread_attr_t *attr, phpspy_thread_func start_routine(void *), void* arg)
{
*thread = (HANDLE*)_beginthreadex(attr, 0, start_routine, arg, 0, NULL);
if (*thread) {
return 0;
} else {
return (int)GetLastError();
}
}

int phpspy_cond_timedwait(phpspy_cond_t *cond, phpspy_mutex_t *mutex, const struct timespec *abstime)
{
DWORD milliseconds = INFINITE;
if (abstime) {
milliseconds = abstime->tv_sec * 1000 + abstime->tv_nsec / 1000000L;
}
if (SleepConditionVariableCS(cond, mutex, milliseconds)) {
return 0;
} else {
return (int)GetLastError();
}
}

#endif /* PHPSPY_WIN32 */
118 changes: 118 additions & 0 deletions basic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#ifndef BASIC_H
#define BASIC_H

#include <stdlib.h>
#include <stdarg.h>

#ifndef PHPSPY_WIN32
#define PHPSPY_PACK __attribute__((__packed__))
#ifndef gettid
#define gettid() syscall(SYS_gettid)
#endif
#endif


#ifdef PHPSPY_WIN32

#include <windows.h>
#include <process.h>
#include <time.h>
#include <tlhelp32.h>
#include <io.h>
#include <stdint.h>
#include <getopt_win.h>
#include <pcre2posix.h>


#define popen _popen
#define pclose _pclose
#define dup _dup
#define dup2 _dup2

#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#endif

#define PHPSPY_PACK
#define gettid() GetCurrentThreadId()
#define getpid() GetCurrentProcessId()
#define PIPE_BUF 4096

struct timezone
{
int tz_minuteswest; /* of Greenwich */
int tz_dsttime; /* type of dst correction to apply */
};

typedef uint32_t pid_t;
typedef __int64 ssize_t;

void nanosleep(struct timespec *ts, void *null);
int asprintf(char** ret, char* fmt, ...);
int gettimeofday(struct timeval* p, void* z);

#endif


/* Thread */
#ifndef PHPSPY_WIN32

typedef pthread_t phpspy_thread_t;
typedef pthread_attr_t phpspy_thread_attr_t;
typedef void *phpspy_thread_func;
#define PHPSPY_THREAD_RETNULL NULL;

typedef pthread_mutex_t phpspy_mutex_t;
typedef pthread_mutexattr_t phpspy_mutexattr_t;
typedef pthread_cond_t phpspy_cond_t;
typedef pthread_condattr_t phpspy_condattr_t;

#define phpspy_thread_create pthread_create
#define phpspy_thread_wait pthread_join
#define phpspy_mutex_init pthread_mutex_init
#define phpspy_mutex_destroy pthread_mutex_destroy
#define phpspy_mutex_lock pthread_mutex_lock
#define phpspy_mutex_unlock pthread_mutex_unlock
#define phpspy_cond_init pthread_cond_init
#define phpspy_cond_destroy pthread_cond_destroy
#define phpspy_cond_timedwait pthread_cond_timedwait
#define phpspy_cond_signal pthread_cond_signal
#define phpspy_cond_broadcast pthread_cond_broadcast

#define phpspy_atomic_add64(ptr, value) __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST);

#endif


#ifdef PHPSPY_WIN32

typedef HANDLE phpspy_thread_t;
typedef SECURITY_ATTRIBUTES phpspy_thread_attr_t;
typedef unsigned __stdcall phpspy_thread_func;
#define PHPSPY_THREAD_RETNULL 0;

typedef CRITICAL_SECTION phpspy_mutex_t;
typedef void phpspy_mutexattr_t;
typedef CONDITION_VARIABLE phpspy_cond_t;
typedef void phpspy_condattr_t;

int phpspy_thread_create(phpspy_thread_t* thread, phpspy_thread_attr_t* attr, phpspy_thread_func start_routine(void*), void* arg);
#define phpspy_thread_wait(thread, value_ptr) WaitForSingleObject(thread, INFINITE)
#define phpspy_mutex_init(mutex, attr) InitializeCriticalSection(mutex)
#define phpspy_mutex_destroy(mutex) DeleteCriticalSection(mutex)
#define phpspy_mutex_lock(mutex) EnterCriticalSection(mutex)
#define phpspy_mutex_unlock(mutex) LeaveCriticalSection(mutex)
#define phpspy_cond_init(cond, attr) InitializeConditionVariable(cond)
#define phpspy_cond_destroy(cond) (void)cond
int phpspy_cond_timedwait(phpspy_cond_t* cond, phpspy_mutex_t* mutex, const struct timespec* abstime);
#define phpspy_cond_signal(cond) WakeConditionVariable(cond)
#define phpspy_cond_broadcast(cond) WakeAllConditionVariable(cond)

#define phpspy_atomic_add64(ptr, value) _InlineInterlockedAdd64(ptr, value);

#endif
/* Thread */

#endif
13 changes: 9 additions & 4 deletions event_fout.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ typedef struct event_handler_fout_udata_s {
static int event_handler_fout_write(event_handler_fout_udata_t *udata);
static int event_handler_fout_snprintf(char **s, size_t *n, size_t *ret_len, int repl_delim, const char *fmt, ...);
static int event_handler_fout_open(int *fd);
static pthread_mutex_t event_handler_fout_mutex = PTHREAD_MUTEX_INITIALIZER;
static phpspy_mutex_t event_handler_fout_mutex;

int event_handler_fout(struct trace_context_s *context, int event_type) {
int rv, fd;
Expand All @@ -39,6 +39,7 @@ int event_handler_fout(struct trace_context_s *context, int event_type) {
udata->use_mutex = context->event_handler_opts != NULL
&& strchr(context->event_handler_opts, 'm') != NULL ? 1 : 0;
context->event_udata = udata;
phpspy_mutex_init(&event_handler_fout_mutex, NULL);
break;
case PHPSPY_TRACE_EVENT_STACK_BEGIN:
udata->cur = udata->buf;
Expand Down Expand Up @@ -140,6 +141,7 @@ int event_handler_fout(struct trace_context_s *context, int event_type) {
close(udata->fd);
free(udata->buf);
free(udata);
phpspy_mutex_destroy(&event_handler_fout_mutex);
break;
}
return PHPSPY_OK;
Expand All @@ -158,7 +160,7 @@ static int event_handler_fout_write(event_handler_fout_udata_t *udata) {
}

if (udata->use_mutex) {
pthread_mutex_lock(&event_handler_fout_mutex);
phpspy_mutex_lock(&event_handler_fout_mutex);
}

if (write(udata->fd, udata->buf, write_len) != write_len) {
Expand All @@ -167,7 +169,7 @@ static int event_handler_fout_write(event_handler_fout_udata_t *udata) {
}

if (udata->use_mutex) {
pthread_mutex_unlock(&event_handler_fout_mutex);
phpspy_mutex_unlock(&event_handler_fout_mutex);
}

return rv;
Expand Down Expand Up @@ -227,8 +229,11 @@ static int event_handler_fout_open(int *fd) {
} else {
path = opt_path_output;
}

#ifdef PHPSPY_WIN32
tfd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
#else
tfd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
errno_saved = errno;

if (apath) {
Expand Down
Loading
Loading