-
-
Notifications
You must be signed in to change notification settings - Fork 10
feature: optimize the case where we are connected but not actively used #65
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -408,6 +408,38 @@ function_stack_entry *xdebug_add_stack_frame(zend_execute_data *zdata, zend_op_a | |
| return tmp; | ||
| } | ||
|
|
||
| static void add_stack_frame_recursively(zend_execute_data *execute_data) | ||
| { | ||
| zend_op_array *op_array; | ||
| int type; | ||
| function_stack_entry *fse; | ||
|
|
||
| if (execute_data->prev_execute_data) { | ||
| add_stack_frame_recursively(execute_data->prev_execute_data); | ||
| } | ||
| if (execute_data->func) { | ||
| op_array = &(execute_data->func->op_array); | ||
| type = ZEND_USER_CODE(execute_data->func->type) ? XDEBUG_USER_DEFINED : XDEBUG_BUILT_IN; | ||
| fse = xdebug_add_stack_frame(execute_data, op_array, type); | ||
| fse->execute_data = execute_data->prev_execute_data; | ||
| if (ZEND_CALL_INFO(execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE) { | ||
| fse->symbol_table = execute_data->symbol_table; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /* | ||
| * This function rebuilds the stack when the debugger is activated after | ||
| * being previously deactivated. This rebuild deliberately does not fire entry side-effects, | ||
| * like recording eval functions or checking function entry breakpoints | ||
| */ | ||
| void xdebug_rebuild_stack(void) | ||
| { | ||
| xdebug_vector_empty(XG_BASE(stack)); | ||
|
|
||
| add_stack_frame_recursively(EG(current_execute_data)); | ||
| } | ||
|
|
||
| /** Function interceptors and dispatchers to modules ***********************/ | ||
|
|
||
| static void xdebug_execute_user_code_begin(zend_execute_data *execute_data) | ||
|
|
@@ -501,6 +533,11 @@ static bool should_run_user_handler(zend_execute_data *execute_data) | |
| return false; | ||
| } | ||
|
|
||
| if (execute_data->func->type == ZEND_EVAL_CODE) | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we are within eval code, we let it be handled by the xdebug_execute_ex function as the normal call using the observers may have been disabled. This allows the debugger to register all eval'd functions, report on them and allow setting breakpoints on them |
||
| { | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -661,7 +661,9 @@ static void xdebug_init_debugger(void) | |
| xdebug_log_ex(XLOG_CHAN_DEBUG, XLOG_ERR, "NOPERM", "No permission connecting to debugging client (%s). This could be SELinux related.", connection_attempts->d); | ||
| } | ||
|
|
||
| XG_BASE(statement_handler_enabled) = XG_DBG(remote_connection_enabled); | ||
| if (XINI_DBG(on_demand_debugging_enabled)) { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only needs to be done for the on_demand mode |
||
| XG_BASE(statement_handler_enabled) = XG_DBG(remote_connection_enabled); | ||
| } | ||
|
|
||
| xdebug_str_free(connection_attempts); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
| #include "ext/standard/info.h" | ||
| #include "zend_exceptions.h" | ||
|
|
||
| #include "base/base.h" | ||
| #include "debugger_private.h" | ||
| #include "frankenphp.h" | ||
| #include "lib/log.h" | ||
|
|
@@ -1231,6 +1232,11 @@ PHP_FUNCTION(xdebug_break) | |
| RETURN_FALSE; | ||
| } | ||
|
|
||
| if (!XG_BASE(observer_active)) { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In xdebug_break we rebuild the stack but we pop the last entry which would correspond to the xdebug_break call and which we don't want to be present |
||
| xdebug_rebuild_stack(); | ||
| xdebug_vector_pop(XG_BASE(stack)); | ||
| } | ||
|
|
||
| xdebug_debug_init_if_requested_on_xdebug_break(); | ||
|
|
||
| if (!xdebug_is_debug_connection_active()) { | ||
|
|
@@ -1240,6 +1246,9 @@ PHP_FUNCTION(xdebug_break) | |
| XG_DBG(context).do_break = 1; | ||
| XG_DBG(context).pending_breakpoint = NULL; | ||
|
|
||
| XG_BASE(statement_handler_enabled) = true; | ||
| XG_BASE(observer_active) = true; | ||
|
|
||
| RETURN_TRUE; | ||
| } | ||
|
|
||
|
|
@@ -1258,7 +1267,13 @@ PHP_FUNCTION(xdebug_connect_to_client) | |
|
|
||
| XG_DBG(context).do_connect_to_client = 1; | ||
|
|
||
| XG_BASE(statement_handler_enabled) = true; | ||
| if (!XG_BASE(observer_active)) { | ||
| xdebug_rebuild_stack(); | ||
| xdebug_vector_pop(XG_BASE(stack)); | ||
| } | ||
|
|
||
| XG_BASE(statement_handler_enabled) = true; | ||
| XG_BASE(observer_active) = true; | ||
|
|
||
| RETURN_TRUE; | ||
| } | ||
|
|
@@ -1283,6 +1298,10 @@ PHP_FUNCTION(xdebug_notify) | |
| return; | ||
| } | ||
|
|
||
| if (!XG_BASE(observer_active)) { | ||
| xdebug_rebuild_stack(); | ||
| } | ||
|
|
||
| fse = xdebug_get_stack_frame(0); | ||
|
|
||
| XG_DBG(context).handler->user_notification( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2493,6 +2493,23 @@ static int xdebug_dbgp_cmdloop(xdebug_con *context, int bail) | |
| free(option); | ||
| } while (0 == ret); | ||
|
|
||
| if (!XG_DBG(context).do_connect_to_client && | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If none of these conditions is true it means that the debugger will not stop at any point (except maybe xdebug_break calls) so we can disable most of the debugger functionality |
||
| !XG_DBG(context).do_break && | ||
| !XG_DBG(context).do_finish && | ||
| !XG_DBG(context).do_next && | ||
| !XG_DBG(context).do_step && | ||
| !XG_DBG(context).send_notifications && | ||
| !xdebug_lib_start_upon_error() && | ||
| (!XG_DBG(context).line_breakpoints || XG_DBG(context).line_breakpoints->size == 0) && | ||
| (!XG_DBG(context).exception_breakpoints || XG_DBG(context).exception_breakpoints->size == 0) && | ||
| (!XG_DBG(context).function_breakpoints || XG_DBG(context).function_breakpoints->size == 0) | ||
| ) { | ||
| if (!XINI_DBG(on_demand_debugging_enabled)) { | ||
| XG_BASE(observer_active) = false; | ||
| } | ||
| XG_BASE(statement_handler_enabled) = false; | ||
| } | ||
|
|
||
| if (bail && XG_DBG(status) == DBGP_STATUS_STOPPED) { | ||
| _zend_bailout((char*)__FILE__, __LINE__); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <?php | ||
| function inner_function() { | ||
| return 42; | ||
| } | ||
|
|
||
| function outer_function() { | ||
| xdebug_break(); | ||
| $result = inner_function(); | ||
| return $result; | ||
| } | ||
|
|
||
| outer_function(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| --TEST-- | ||
| Stack is correctly rebuilt after xdebug_break() with on_demand_debugging_enabled=0 | ||
| --SKIPIF-- | ||
| <?php | ||
| require __DIR__ . '/../utils.inc'; | ||
| check_reqs('dbgp'); | ||
| ?> | ||
| --FILE-- | ||
| <?php | ||
| require 'dbgp/dbgpclient.php'; | ||
|
|
||
| $filename = dirname(__FILE__) . '/rebuild-stack-after-xdebug-break.inc'; | ||
|
|
||
| $commands = array( | ||
| 'run', | ||
| 'stack_get', | ||
| 'step_into', | ||
| 'stack_get', | ||
| 'step_out', | ||
| 'stack_get', | ||
| 'detach', | ||
| ); | ||
|
|
||
| $settings = [ | ||
| 'xdebug.mode' => 'debug', | ||
| 'xdebug.start_with_request' => 'yes', | ||
| 'xdebug.on_demand_debugging_enabled' => 0 | ||
| ]; | ||
|
|
||
| dbgpRunFile( $filename, $commands, $settings ); | ||
| ?> | ||
| --EXPECTF-- | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file://rebuild-stack-after-xdebug-break.inc" language="PHP" xdebug:language_version="" protocol_version="1.0" appid=""><engine version=""><![CDATA[PHP Debugger]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2099 by Derick Rethans]]></copyright></init> | ||
|
|
||
| -> run -i 1 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="run" transaction_id="1" status="break" reason="ok"><xdebug:message filename="file://rebuild-stack-after-xdebug-break.inc" lineno="8"></xdebug:message></response> | ||
|
|
||
| -> stack_get -i 2 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stack_get" transaction_id="2"><stack where="outer_function" level="0" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="8"></stack><stack where="{main}" level="1" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="12"></stack></response> | ||
|
|
||
| -> step_into -i 3 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="step_into" transaction_id="3" status="break" reason="ok"><xdebug:message filename="file://rebuild-stack-after-xdebug-break.inc" lineno="3"></xdebug:message></response> | ||
|
|
||
| -> stack_get -i 4 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stack_get" transaction_id="4"><stack where="inner_function" level="0" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="3"></stack><stack where="outer_function" level="1" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="8"></stack><stack where="{main}" level="2" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="12"></stack></response> | ||
|
|
||
| -> step_out -i 5 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="step_out" transaction_id="5" status="break" reason="ok"><xdebug:message filename="file://rebuild-stack-after-xdebug-break.inc" lineno="9"></xdebug:message></response> | ||
|
|
||
| -> stack_get -i 6 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stack_get" transaction_id="6"><stack where="outer_function" level="0" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="9"></stack><stack where="{main}" level="1" type="file" filename="file://rebuild-stack-after-xdebug-break.inc" lineno="12"></stack></response> | ||
|
|
||
| -> detach -i 7 | ||
| <?xml version="1.0" encoding="iso-8859-1"?> | ||
| <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="detach" transaction_id="7" status="stopping" reason="ok"></response> |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a couple of cases (when stopping on xdebug_break or when responding to a xdebug_notify call) we may need to rebuild the stack, because we would not have been keeping it updated because we disabled the debugger as it was not being actively used. This function is used to rebuild the stack from the current execute data recursively