Skip to content

Commit 27de54b

Browse files
author
Andi Gutmans
committed
- MFZE1
1 parent f222884 commit 27de54b

File tree

3 files changed

+204
-0
lines changed

3 files changed

+204
-0
lines changed

Zend/zend.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,34 @@ static void print_hash(HashTable *ht, int indent)
134134
ZEND_PUTS(")\n");
135135
}
136136

137+
static void print_flat_hash(HashTable *ht)
138+
{
139+
zval **tmp;
140+
char *string_key;
141+
HashPosition iterator;
142+
ulong num_key;
143+
uint str_len;
144+
int i = 0;
145+
146+
zend_hash_internal_pointer_reset_ex(ht, &iterator);
147+
while (zend_hash_get_current_data_ex(ht, (void **) &tmp, &iterator) == SUCCESS) {
148+
if (i++ > 0) {
149+
ZEND_PUTS(",");
150+
}
151+
ZEND_PUTS("[");
152+
switch (zend_hash_get_current_key_ex(ht, &string_key, &str_len, &num_key, 0, &iterator)) {
153+
case HASH_KEY_IS_STRING:
154+
ZEND_PUTS(string_key);
155+
break;
156+
case HASH_KEY_IS_LONG:
157+
zend_printf("%ld", num_key);
158+
break;
159+
}
160+
ZEND_PUTS("] => ");
161+
zend_print_flat_zval_r(*tmp);
162+
zend_hash_move_forward_ex(ht, &iterator);
163+
}
164+
}
137165

138166
ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy)
139167
{
@@ -216,6 +244,42 @@ ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int in
216244
return expr->value.str.len;
217245
}
218246

247+
ZEND_API void zend_print_flat_zval_r(zval *expr)
248+
{
249+
zend_write_func_t write_func = zend_write;
250+
251+
switch (expr->type) {
252+
case IS_ARRAY:
253+
ZEND_PUTS("Array (");
254+
if (++expr->value.ht->nApplyCount>1) {
255+
ZEND_PUTS(" *RECURSION*");
256+
expr->value.ht->nApplyCount--;
257+
return;
258+
}
259+
print_flat_hash(expr->value.ht);
260+
ZEND_PUTS(")");
261+
expr->value.ht->nApplyCount--;
262+
break;
263+
case IS_OBJECT:
264+
{
265+
zend_object *object = Z_OBJ_P(expr);
266+
267+
if (++object->properties->nApplyCount>1) {
268+
ZEND_PUTS(" *RECURSION*");
269+
object->properties->nApplyCount--;
270+
return;
271+
}
272+
zend_printf("%s Object (", object->ce->name);
273+
print_flat_hash(object->properties);
274+
ZEND_PUTS(")");
275+
object->properties->nApplyCount--;
276+
break;
277+
}
278+
default:
279+
zend_print_variable(expr);
280+
break;
281+
}
282+
}
219283

220284
ZEND_API void zend_print_zval_r(zval *expr, int indent)
221285
{

Zend/zend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop
431431
ZEND_API int zend_print_zval(zval *expr, int indent);
432432
ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent);
433433
ZEND_API void zend_print_zval_r(zval *expr, int indent);
434+
ZEND_API void zend_print_flat_zval_r(zval *expr);
434435
ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent);
435436
ZEND_API void zend_output_debug_string(zend_bool trigger_break, char *format, ...);
436437

Zend/zend_builtin_functions.c

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static ZEND_FUNCTION(extension_loaded);
7070
static ZEND_FUNCTION(get_extension_funcs);
7171
static ZEND_FUNCTION(get_defined_constants);
7272
static ZEND_FUNCTION(debug_backtrace);
73+
static ZEND_FUNCTION(debug_print_backtrace);
7374
#if ZEND_DEBUG
7475
static ZEND_FUNCTION(zend_test_func);
7576
#ifdef ZTS
@@ -129,6 +130,7 @@ static zend_function_entry builtin_functions[] = {
129130
ZEND_FE(get_extension_funcs, NULL)
130131
ZEND_FE(get_defined_constants, NULL)
131132
ZEND_FE(debug_backtrace, NULL)
133+
ZEND_FE(debug_print_backtrace, NULL)
132134
#if ZEND_DEBUG
133135
ZEND_FE(zend_test_func, NULL)
134136
#ifdef ZTS
@@ -1296,6 +1298,143 @@ static zval *debug_backtrace_get_args(void ***curpos TSRMLS_DC) {
12961298
return arg_array;
12971299
}
12981300

1301+
void debug_print_backtrace_args(zval *arg_array)
1302+
{
1303+
zval **tmp;
1304+
HashPosition iterator;
1305+
int i = 0;
1306+
1307+
zend_hash_internal_pointer_reset_ex(arg_array->value.ht, &iterator);
1308+
while (zend_hash_get_current_data_ex(arg_array->value.ht, (void **) &tmp, &iterator) == SUCCESS) {
1309+
if (i++) {
1310+
ZEND_PUTS(", ");
1311+
}
1312+
zend_print_flat_zval_r(*tmp);
1313+
zend_hash_move_forward_ex(arg_array->value.ht, &iterator);
1314+
}
1315+
}
1316+
1317+
/* {{{ proto void debug_print_backtrace(void) */
1318+
ZEND_FUNCTION(debug_print_backtrace)
1319+
{
1320+
zend_execute_data *ptr;
1321+
int lineno;
1322+
char *function_name;
1323+
char *filename;
1324+
char *class_name;
1325+
char *call_type;
1326+
char *include_filename = NULL;
1327+
zval *arg_array;
1328+
void **cur_arg_pos = EG(argument_stack).top_element;
1329+
void **args = cur_arg_pos;
1330+
int arg_stack_consistent = 0;
1331+
int frames_on_stack = 0;
1332+
int indent;
1333+
1334+
if (ZEND_NUM_ARGS()) {
1335+
ZEND_WRONG_PARAM_COUNT();
1336+
}
1337+
1338+
while (--args >= EG(argument_stack).elements) {
1339+
if (*args--) {
1340+
break;
1341+
}
1342+
args -= *(ulong*)args;
1343+
frames_on_stack++;
1344+
1345+
if (args == EG(argument_stack).elements) {
1346+
arg_stack_consistent = 1;
1347+
break;
1348+
}
1349+
}
1350+
1351+
ptr = EG(current_execute_data);
1352+
1353+
/* skip debug_backtrace() */
1354+
ptr = ptr->prev_execute_data;
1355+
cur_arg_pos -= 2;
1356+
frames_on_stack--;
1357+
1358+
array_init(return_value);
1359+
1360+
while (ptr) {
1361+
if (ptr->op_array) {
1362+
filename = ptr->op_array->filename;
1363+
lineno = ptr->opline->lineno;
1364+
} else {
1365+
filename = NULL;
1366+
}
1367+
1368+
function_name = ptr->function_state.function->common.function_name;
1369+
1370+
if (function_name) {
1371+
if (ptr->object) {
1372+
class_name = Z_OBJCE(*ptr->object)->name;
1373+
call_type = "->";
1374+
} else if (ptr->function_state.function->common.scope) {
1375+
class_name = ptr->function_state.function->common.scope->name;
1376+
call_type = "::";
1377+
} else {
1378+
class_name = NULL;
1379+
call_type = NULL;
1380+
}
1381+
if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) {
1382+
if (arg_stack_consistent && (frames_on_stack > 0)) {
1383+
arg_array = debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC);
1384+
frames_on_stack--;
1385+
}
1386+
}
1387+
} else {
1388+
/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
1389+
zend_bool build_filename_arg = 1;
1390+
1391+
switch (ptr->opline->op2.u.constant.value.lval) {
1392+
case ZEND_EVAL:
1393+
function_name = "eval";
1394+
build_filename_arg = 0;
1395+
break;
1396+
case ZEND_INCLUDE:
1397+
function_name = "include";
1398+
break;
1399+
case ZEND_REQUIRE:
1400+
function_name = "require";
1401+
break;
1402+
case ZEND_INCLUDE_ONCE:
1403+
function_name = "include_once";
1404+
break;
1405+
case ZEND_REQUIRE_ONCE:
1406+
function_name = "require_once";
1407+
break;
1408+
default:
1409+
/* this can actually happen if you use debug_backtrace() in your error_handler and
1410+
* you're in the top-scope */
1411+
function_name = "unknown";
1412+
build_filename_arg = 0;
1413+
break;
1414+
}
1415+
1416+
if (build_filename_arg && include_filename) {
1417+
MAKE_STD_ZVAL(arg_array);
1418+
array_init(arg_array);
1419+
add_next_index_string(arg_array, include_filename, 1);
1420+
}
1421+
}
1422+
zend_printf("#%-2d ", indent);
1423+
if (class_name) {
1424+
ZEND_PUTS(class_name);
1425+
ZEND_PUTS(call_type);
1426+
}
1427+
zend_printf("%s(", function_name?function_name:"main");
1428+
debug_print_backtrace_args(arg_array);
1429+
ZVAL_DELREF(arg_array);
1430+
zend_printf(") called at [%s:%d]\n", filename, lineno);
1431+
include_filename = filename;
1432+
ptr = ptr->prev_execute_data;
1433+
++indent;
1434+
}
1435+
}
1436+
1437+
/* }}} */
12991438
/* {{{ proto void debug_backtrace(void)
13001439
Prints out a backtrace */
13011440
ZEND_FUNCTION(debug_backtrace)

0 commit comments

Comments
 (0)