Skip to content

Commit 29aad0e

Browse files
committed
Add phpdbg userland API to fetch oplog
We may want to add some opcode info later, so that "opcodes" mode is more helpful
1 parent 44d545b commit 29aad0e

4 files changed

Lines changed: 174 additions & 2 deletions

File tree

sapi/phpdbg/phpdbg.c

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,7 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
245245
PHPDBG_G(prompt)[1] = NULL;
246246

247247
if (PHPDBG_G(oplog)) {
248-
fclose(
249-
PHPDBG_G(oplog));
248+
fclose(PHPDBG_G(oplog));
250249
PHPDBG_G(oplog) = NULL;
251250
}
252251

@@ -256,6 +255,18 @@ static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
256255
PHPDBG_G(ops) = NULL;
257256
}
258257

258+
if (PHPDBG_G(oplog_list)) {
259+
phpdbg_oplog_list *cur = PHPDBG_G(oplog_list);
260+
do {
261+
phpdbg_oplog_list *prev = cur->prev;
262+
efree(cur);
263+
cur = prev;
264+
} while (cur != NULL);
265+
266+
zend_arena_destroy(PHPDBG_G(oplog_arena));
267+
PHPDBG_G(oplog_list) = NULL;
268+
}
269+
259270
return SUCCESS;
260271
} /* }}} */
261272

@@ -403,6 +414,132 @@ static PHP_FUNCTION(phpdbg_prompt)
403414
phpdbg_set_prompt(prompt);
404415
} /* }}} */
405416

417+
/* {{{ proto void phpdbg_start_oplog() */
418+
static PHP_FUNCTION(phpdbg_start_oplog)
419+
{
420+
phpdbg_oplog_list *prev;
421+
422+
if (zend_parse_parameters_none() == FAILURE) {
423+
return;
424+
}
425+
426+
prev = PHPDBG_G(oplog_list);
427+
428+
if (!prev) {
429+
PHPDBG_G(oplog_arena) = zend_arena_create(64 * 1024);
430+
431+
PHPDBG_G(oplog_cur) = ((phpdbg_oplog_entry *) zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry))) + 1;
432+
PHPDBG_G(oplog_cur)->next = NULL;
433+
}
434+
435+
PHPDBG_G(oplog_list) = emalloc(sizeof(phpdbg_oplog_list));
436+
PHPDBG_G(oplog_list)->prev = prev;
437+
PHPDBG_G(oplog_list)->start = PHPDBG_G(oplog_cur);
438+
}
439+
440+
/* {{{ proto void phpdbg_end_oplog() */
441+
static PHP_FUNCTION(phpdbg_end_oplog)
442+
{
443+
phpdbg_oplog_entry *cur = PHPDBG_G(oplog_list)->start;
444+
phpdbg_oplog_list *prev = PHPDBG_G(oplog_list)->prev;
445+
446+
HashTable *options;
447+
zval *option_buffer;
448+
zend_bool by_function = 0;
449+
zend_bool by_opcode = 0;
450+
451+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) {
452+
return;
453+
}
454+
455+
if (!PHPDBG_G(oplog_list)) {
456+
zend_error(E_WARNING, "Can not end an oplog without starting it");
457+
return;
458+
}
459+
460+
efree(PHPDBG_G(oplog_list));
461+
PHPDBG_G(oplog_list) = prev;
462+
463+
if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("functions")))) {
464+
by_function = zend_is_true(option_buffer);
465+
}
466+
467+
if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("opcodes")))) {
468+
if (by_function) {
469+
by_opcode = zend_is_true(option_buffer);
470+
}
471+
}
472+
473+
array_init(return_value);
474+
475+
{
476+
zend_string *last_file = NULL;
477+
zval *file_buf;
478+
zend_string *last_function = (void *)~(uintptr_t)0;
479+
zend_class_entry *last_scope = NULL;
480+
zval *fn_buf;
481+
482+
HashTable *insert_ht;
483+
zend_long insert_idx;
484+
485+
do {
486+
zend_op_array *op_array = cur->op_array;
487+
if (op_array->filename != last_file) {
488+
last_file = op_array->filename;
489+
file_buf = zend_hash_find(Z_ARR_P(return_value), last_file);
490+
if (!file_buf) {
491+
zval ht;
492+
array_init(&ht);
493+
file_buf = zend_hash_add_new(Z_ARR_P(return_value), last_file, &ht);
494+
}
495+
}
496+
insert_ht = Z_ARR_P(file_buf);
497+
498+
if (by_function) {
499+
if (op_array->function_name != last_function || op_array->scope != last_scope) {
500+
zend_string *fn_name;
501+
last_function = op_array->function_name;
502+
last_scope = op_array->scope;
503+
if (last_scope == NULL) {
504+
fn_name = zend_string_copy(last_function);
505+
} else {
506+
fn_name = strpprintf(last_function->len + last_scope->name->len + 2, "%.*s::%.*s", last_function->len, last_function->val, last_scope->name->len, last_scope->name->val);
507+
}
508+
fn_buf = zend_hash_find(Z_ARR_P(return_value), fn_name);
509+
if (!fn_buf) {
510+
zval ht;
511+
array_init(&ht);
512+
fn_buf = zend_hash_add_new(Z_ARR_P(return_value), fn_name, &ht);
513+
}
514+
}
515+
insert_ht = Z_ARR_P(fn_buf);
516+
}
517+
518+
if (by_opcode) {
519+
insert_idx = cur->op - op_array->opcodes;
520+
} else {
521+
insert_idx = cur->op->lineno;
522+
}
523+
524+
{
525+
zval *num = zend_hash_index_find(insert_ht, insert_idx);
526+
if (!num) {
527+
zval zv;
528+
ZVAL_LONG(&zv, 0);
529+
num = zend_hash_index_add_new(insert_ht, insert_idx, &zv);
530+
}
531+
Z_LVAL_P(num)++;
532+
}
533+
534+
cur = cur->next;
535+
} while (cur != NULL);
536+
}
537+
538+
if (!prev) {
539+
zend_arena_destroy(PHPDBG_G(oplog_arena));
540+
}
541+
}
542+
406543
ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)
407544
ZEND_END_ARG_INFO()
408545

@@ -436,6 +573,12 @@ ZEND_END_ARG_INFO()
436573
ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
437574
ZEND_END_ARG_INFO()
438575

576+
ZEND_BEGIN_ARG_INFO_EX(phpdbg_start_oplog_arginfo, 0, 0, 0)
577+
ZEND_END_ARG_INFO()
578+
579+
ZEND_BEGIN_ARG_INFO_EX(phpdbg_end_oplog_arginfo, 0, 0, 0)
580+
ZEND_END_ARG_INFO()
581+
439582
zend_function_entry phpdbg_user_functions[] = {
440583
PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
441584
PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo)
@@ -445,6 +588,8 @@ zend_function_entry phpdbg_user_functions[] = {
445588
PHP_FE(phpdbg_exec, phpdbg_exec_arginfo)
446589
PHP_FE(phpdbg_color, phpdbg_color_arginfo)
447590
PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
591+
PHP_FE(phpdbg_start_oplog, phpdbg_start_oplog_arginfo)
592+
PHP_FE(phpdbg_end_oplog, phpdbg_end_oplog_arginfo)
448593
#ifdef PHP_FE_END
449594
PHP_FE_END
450595
#else

sapi/phpdbg/phpdbg.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
#include "phpdbg_btree.h"
131131
#include "phpdbg_watch.h"
132132
#include "phpdbg_bp.h"
133+
#include "phpdbg_opcode.h"
133134
#ifdef PHP_WIN32
134135
# include "phpdbg_sigio_win32.h"
135136
#endif
@@ -264,6 +265,10 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
264265
HashTable file_sources;
265266

266267
FILE *oplog; /* opline log */
268+
zend_arena *oplog_arena; /* arena for storing oplog */
269+
phpdbg_oplog_list *oplog_list; /* list of oplog starts */
270+
phpdbg_oplog_entry *oplog_cur; /* current oplog entry */
271+
267272
struct {
268273
FILE *ptr;
269274
int fd;

sapi/phpdbg/phpdbg_opcode.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, ze
226226
free(decode);
227227
}
228228
}
229+
230+
if (PHPDBG_G(oplog_list)) {
231+
phpdbg_oplog_entry *cur = zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry));
232+
cur->op = (zend_op *) execute_data->opline;
233+
cur->op_array = &execute_data->func->op_array;
234+
cur->next = NULL;
235+
PHPDBG_G(oplog_cur)->next = cur;
236+
PHPDBG_G(oplog_cur) = cur;
237+
}
229238
} /* }}} */
230239

231240
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags) /* {{{ */

sapi/phpdbg/phpdbg_opcode.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,17 @@ char *phpdbg_decode_opline(zend_op_array *ops, zend_op *op, HashTable *vars);
2828
void phpdbg_print_opline(zend_execute_data *execute_data, zend_bool ignore_flags);
2929
void phpdbg_print_opline_ex(zend_execute_data *execute_data, HashTable *vars, zend_bool ignore_flags);
3030

31+
typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry;
32+
struct _phpdbg_oplog_entry {
33+
phpdbg_oplog_entry *next;
34+
zend_op_array *op_array;
35+
zend_op *op;
36+
};
37+
38+
typedef struct _phpdbg_oplog_list phpdbg_oplog_list;
39+
struct _phpdbg_oplog_list {
40+
phpdbg_oplog_list *prev;
41+
phpdbg_oplog_entry *start;
42+
};
43+
3144
#endif /* PHPDBG_OPCODE_H */

0 commit comments

Comments
 (0)