1 Star 0 Fork 347

黑冰/swoole-src

forked from swoole/swoole-src 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
swoole_trace.c 14.43 KB
一键复制 编辑 原始数据 按行查看 历史
twosee 提交于 2019-04-16 16:58 . PHP7.4 compatibility - 2 (#2506).
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "php_swoole.h"
#ifdef HAVE_PTRACE
#include <stddef.h>
#include <sys/ptrace.h>
#if SIZEOF_LONG == 4
#define PTR_FMT "08"
#elif SIZEOF_LONG == 8
#define PTR_FMT "016"
#endif
#if defined(PT_ATTACH) && !defined(PTRACE_ATTACH)
#if __APPLE__
#define PTRACE_ATTACH PT_ATTACHEXC
#else
#define PTRACE_ATTACH PT_ATTACH
#endif
#endif
#if defined(PT_DETACH) && !defined(PTRACE_DETACH)
#define PTRACE_DETACH PT_DETACH
#endif
#if defined(PT_READ_D) && !defined(PTRACE_PEEKDATA)
#define PTRACE_PEEKDATA PT_READ_D
#endif
#define valid_ptr(p) ((p) && 0 == ((p) & (sizeof(long) - 1)))
static void trace_request(swWorker *worker);
static int trace_dump(swWorker *worker, FILE *slowlog);
static int trace_get_long(pid_t traced_pid, long addr, long *data);
static int trace_get_strz(pid_t traced_pid, char *buf, size_t sz, long addr);
static void trace_request(swWorker *worker)
{
FILE *slowlog = SwooleG.serv->request_slowlog_file;
pid_t traced_pid = worker->pid;
int ret = trace_dump(worker, slowlog);
if (ret < 0)
{
swSysWarn("failed to trace worker %d, error lint =%d", worker->pid, -ret);
}
if (0 > ptrace(PTRACE_DETACH, traced_pid, (void *) 1, 0))
{
swSysWarn("failed to ptrace(DETACH) worker %d", worker->pid);
}
fflush(slowlog);
}
void php_swoole_trace_check(void *arg)
{
swServer *serv = (swServer *) arg;
uint8_t timeout = serv->request_slowlog_timeout;
int count = serv->worker_num + serv->task_worker_num;
int i = serv->trace_event_worker ? 0 : serv->worker_num;
swWorker *worker;
for (; i < count; i++)
{
worker = swServer_get_worker(serv, i);
swTraceLog(SW_TRACE_SERVER, "trace request, worker#%d, pid=%d. request_time=%ld", i, worker->pid, worker->request_time);
if (!(worker->request_time > 0 && worker->traced == 0 && serv->gs->now - worker->request_time >= timeout))
{
continue;
}
if (ptrace(PTRACE_ATTACH, worker->pid, 0, 0) < 0)
{
swSysWarn("failed to ptrace(ATTACH, %d) worker#%d,", worker->pid, worker->id);
continue;
}
worker->tracer = trace_request;
worker->traced = 1;
}
}
static int trace_get_long(pid_t traced_pid, long addr, long *data)
{
errno = 0;
*data = ptrace(PTRACE_PEEKDATA, traced_pid, (void *) addr, 0);
if (*data < 0)
{
return -1;
}
return 0;
}
static int trace_get_strz(pid_t traced_pid, char *buf, size_t sz, long addr)
{
int i;
long l = addr;
char *lc = (char *) &l;
i = l % SIZEOF_LONG;
l -= i;
for (addr = l;; addr += SIZEOF_LONG)
{
if (0 > trace_get_long(traced_pid, addr, &l))
{
return -1;
}
for (; i < SIZEOF_LONG; i++)
{
--sz;
if (sz && lc[i])
{
*buf++ = lc[i];
continue;
}
*buf = '\0';
return 0;
}
i = 0;
}
return 0;
}
size_t trace_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len)
{
struct tm t;
size_t len;
len = strftime(timebuf, timebuf_len, "[%d-%b-%Y %H:%M:%S", localtime_r((const time_t *) &tv->tv_sec, &t));
len += sw_snprintf(timebuf + len, timebuf_len - len, "] ");
return len;
}
static int trace_dump(swWorker *worker, FILE *slowlog)
{
pid_t traced_pid = worker->pid;
int callers_limit = 100;
struct timeval tv;
static const int buf_size = 1024;
char buf[buf_size];
long execute_data;
long l;
gettimeofday(&tv, 0);
trace_print_time(&tv, buf, buf_size);
fprintf(slowlog, "\n%s [worker#%d] pid %d\n", buf, worker->id, (int) traced_pid);
if (0 > trace_get_long(traced_pid, (long) &EG(current_execute_data), &l))
{
return -__LINE__;
}
execute_data = l;
#if PHP_VERSION_ID > 70100
while (execute_data)
{
long function;
long function_name;
long file_name;
long prev;
uint32_t lineno = 0;
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, func), &l))
{
return -__LINE__;
}
function = l;
if (valid_ptr(function))
{
if (0 > trace_get_long(traced_pid, function + offsetof(zend_function, common.function_name), &l))
{
return -1;
}
function_name = l;
if (function_name == 0)
{
uint32_t *call_info = (uint32_t *) &l;
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, This.u1.type_info), &l))
{
return -__LINE__;
}
#if PHP_VERSION_ID < 70400
if (ZEND_CALL_KIND_EX((*call_info) >> ZEND_CALL_INFO_SHIFT) == ZEND_CALL_TOP_CODE)
#else
if (ZEND_CALL_KIND_EX(*call_info) == ZEND_CALL_TOP_CODE)
#endif
{
return 0;
}
#if PHP_VERSION_ID < 70400
else if (ZEND_CALL_KIND_EX(*(call_info) >> ZEND_CALL_INFO_SHIFT) == ZEND_CALL_NESTED_CODE)
#else
else if (ZEND_CALL_KIND_EX(*call_info) == ZEND_CALL_NESTED_CODE)
#endif
{
memcpy(buf, "[INCLUDE_OR_EVAL]", sizeof("[INCLUDE_OR_EVAL]"));
}
else
{
ZEND_ASSERT(0);
}
}
else
{
if (0 > trace_get_strz(traced_pid, buf, buf_size, function_name + offsetof(zend_string, val)))
{
return -__LINE__;
}
}
}
else
{
memcpy(buf, "???", sizeof("???"));
}
fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data);
fprintf(slowlog, "%s()", buf);
*buf = '\0';
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, prev_execute_data), &l))
{
return -__LINE__;
}
execute_data = prev = l;
while (prev)
{
zend_uchar *type;
if (0 > trace_get_long(traced_pid, prev + offsetof(zend_execute_data, func), &l))
{
return -__LINE__;
}
function = l;
if (!valid_ptr(function))
{
break;
}
type = (zend_uchar *) &l;
if (0 > trace_get_long(traced_pid, function + offsetof(zend_function, type), &l))
{
return -__LINE__;
}
if (ZEND_USER_CODE(*type))
{
if (0 > trace_get_long(traced_pid, function + offsetof(zend_op_array, filename), &l))
{
return -__LINE__;
}
file_name = l;
if (0 > trace_get_strz(traced_pid, buf, buf_size, file_name + offsetof(zend_string, val)))
{
return -__LINE__;
}
if (0 > trace_get_long(traced_pid, prev + offsetof(zend_execute_data, opline), &l))
{
return -__LINE__;
}
if (valid_ptr(l))
{
long opline = l;
uint32_t *lu = (uint32_t *) &l;
if (0 > trace_get_long(traced_pid, opline + offsetof(struct _zend_op, lineno), &l))
{
return -__LINE__;
}
lineno = *lu;
}
break;
}
if (0 > trace_get_long(traced_pid, prev + offsetof(zend_execute_data, prev_execute_data), &l))
{
return -__LINE__;
}
prev = l;
}
fprintf(slowlog, " %s:%u\n", *buf ? buf : "unknown", lineno);
if (0 == --callers_limit)
{
break;
}
}
#elif PHP_VERSION_ID >= 70000
while (execute_data)
{
long function;
long function_name;
long file_name;
long prev;
uint lineno = 0;
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, func), &l))
{
return -1;
}
function = l;
if (valid_ptr(function))
{
if (0 > trace_get_long(traced_pid, function + offsetof(zend_function, common.function_name), &l))
{
return -1;
}
function_name = l;
if (function_name == 0)
{
uint32_t *call_info = (uint32_t *)&l;
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, This.u1.type_info), &l))
{
return -1;
}
if (ZEND_CALL_KIND_EX((*call_info) >> 24) == ZEND_CALL_TOP_CODE)
{
return 0;
}
else if (ZEND_CALL_KIND_EX(*(call_info) >> 24) == ZEND_CALL_NESTED_CODE)
{
memcpy(buf, "[INCLUDE_OR_EVAL]", sizeof("[INCLUDE_OR_EVAL]"));
}
else
{
ZEND_ASSERT(0);
}
}
else
{
if (0 > trace_get_strz(traced_pid, buf, buf_size, function_name + offsetof(zend_string, val)))
{
return -1;
}
}
}
else
{
memcpy(buf, "???", sizeof("???"));
}
fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data);
fprintf(slowlog, "%s()", buf);
*buf = '\0';
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, prev_execute_data), &l))
{
return -1;
}
execute_data = prev = l;
while (prev)
{
zend_uchar *type;
if (0 > trace_get_long(traced_pid, prev + offsetof(zend_execute_data, func), &l))
{
return -1;
}
function = l;
if (!valid_ptr(function))
{
break;
}
type = (zend_uchar *)&l;
if (0 > trace_get_long(traced_pid, function + offsetof(zend_function, type), &l))
{
return -1;
}
if (ZEND_USER_CODE(*type))
{
if (0 > trace_get_long(traced_pid, function + offsetof(zend_op_array, filename), &l))
{
return -1;
}
file_name = l;
if (0 > trace_get_strz(traced_pid, buf, buf_size, file_name + offsetof(zend_string, val)))
{
return -1;
}
if (0 > trace_get_long(traced_pid, prev + offsetof(zend_execute_data, opline), &l))
{
return -1;
}
if (valid_ptr(l))
{
long opline = l;
uint32_t *lu = (uint32_t *) &l;
if (0 > trace_get_long(traced_pid, opline + offsetof(struct _zend_op, lineno), &l))
{
return -1;
}
lineno = *lu;
}
break;
}
if (0 > trace_get_long(traced_pid, prev + offsetof(zend_execute_data, prev_execute_data), &l))
{
return -1;
}
prev = l;
}
fprintf(slowlog, " %s:%u\n", *buf ? buf : "unknown", lineno);
if (0 == --callers_limit)
{
break;
}
}
#else
while (execute_data)
{
long function;
uint lineno = 0;
fprintf(slowlog, "[0x%" PTR_FMT "lx] ", execute_data);
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, function_state.function), &l))
{
return -1;
}
function = l;
if (valid_ptr(function))
{
if (0 > trace_get_strz(traced_pid, buf, buf_size, function + offsetof(zend_function, common.function_name)))
{
return -1;
}
fprintf(slowlog, "%s()", buf);
}
else
{
fprintf(slowlog, "???");
}
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, op_array), &l))
{
return -1;
}
*buf = '\0';
if (valid_ptr(l))
{
long op_array = l;
if (0 > trace_get_strz(traced_pid, buf, buf_size, op_array + offsetof(zend_op_array, filename)))
{
return -1;
}
}
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, opline), &l))
{
return -1;
}
if (valid_ptr(l))
{
long opline = l;
uint *lu = (uint *) &l;
if (0 > trace_get_long(traced_pid, opline + offsetof(struct _zend_op, lineno), &l))
{
return -1;
}
lineno = *lu;
}
fprintf(slowlog, " %s:%u\n", *buf ? buf : "unknown", lineno);
if (0 > trace_get_long(traced_pid, execute_data + offsetof(zend_execute_data, prev_execute_data), &l))
{
return -1;
}
execute_data = l;
if (0 == --callers_limit)
{
break;
}
}
#endif
return 0;
}
#endif
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/whoneed/swoole.git
git@gitee.com:whoneed/swoole.git
whoneed
swoole
swoole-src
master

搜索帮助