2018-03-15 02:13:07 +03:00
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2015-10-19 05:25:20 +03:00
/*******************************************************************************
*
* Module Name : dbxface - AML Debugger external interfaces
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <acpi/acpi.h>
# include "accommon.h"
# include "amlcode.h"
# include "acdebug.h"
2017-04-26 11:18:33 +03:00
# include "acinterp.h"
2018-08-11 00:42:59 +03:00
# include "acparser.h"
2015-10-19 05:25:20 +03:00
# define _COMPONENT ACPI_CA_DEBUGGER
ACPI_MODULE_NAME ( " dbxface " )
/* Local prototypes */
static acpi_status
acpi_db_start_command ( struct acpi_walk_state * walk_state ,
union acpi_parse_object * op ) ;
# ifdef ACPI_OBSOLETE_FUNCTIONS
void acpi_db_method_end ( struct acpi_walk_state * walk_state ) ;
# endif
2018-11-05 20:43:51 +03:00
# ifdef ACPI_DISASSEMBLER
static union acpi_parse_object * acpi_db_get_display_op ( struct acpi_walk_state
* walk_state ,
union acpi_parse_object
* op ) ;
# endif
2015-10-19 05:25:20 +03:00
/*******************************************************************************
*
* FUNCTION : acpi_db_start_command
*
* PARAMETERS : walk_state - Current walk
* op - Current executing Op , from AML interpreter
*
* RETURN : Status
*
* DESCRIPTION : Enter debugger command loop
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static acpi_status
acpi_db_start_command ( struct acpi_walk_state * walk_state ,
union acpi_parse_object * op )
{
acpi_status status ;
/* TBD: [Investigate] are there namespace locking issues here? */
/* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
/* Go into the command loop and await next user command */
acpi_gbl_method_executing = TRUE ;
status = AE_CTRL_TRUE ;
2015-12-03 05:42:46 +03:00
while ( status = = AE_CTRL_TRUE ) {
2015-10-19 05:25:20 +03:00
2015-12-03 05:42:46 +03:00
/* Notify the completion of the command */
2015-10-19 05:25:20 +03:00
2015-12-03 05:42:46 +03:00
status = acpi_os_notify_command_complete ( ) ;
if ( ACPI_FAILURE ( status ) ) {
goto error_exit ;
}
2015-10-19 05:25:20 +03:00
2015-12-03 05:42:46 +03:00
/* Wait the readiness of the command */
2015-10-19 05:25:20 +03:00
2015-12-03 05:42:46 +03:00
status = acpi_os_wait_command_ready ( ) ;
if ( ACPI_FAILURE ( status ) ) {
goto error_exit ;
2015-10-19 05:25:20 +03:00
}
status =
acpi_db_command_dispatch ( acpi_gbl_db_line_buf , walk_state ,
op ) ;
}
/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
2015-12-03 05:42:46 +03:00
error_exit :
if ( ACPI_FAILURE ( status ) & & status ! = AE_CTRL_TERMINATE ) {
ACPI_EXCEPTION ( ( AE_INFO , status ,
" While parsing/handling command line " ) ) ;
}
2015-10-19 05:25:20 +03:00
return ( status ) ;
}
2015-12-03 05:42:53 +03:00
/*******************************************************************************
*
* FUNCTION : acpi_db_signal_break_point
*
* PARAMETERS : walk_state - Current walk
*
* RETURN : Status
*
2017-04-26 11:18:40 +03:00
* DESCRIPTION : Called for AML_BREAKPOINT_OP
2015-12-03 05:42:53 +03:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void acpi_db_signal_break_point ( struct acpi_walk_state * walk_state )
{
# ifndef ACPI_APPLICATION
if ( acpi_gbl_db_thread_id ! = acpi_os_get_thread_id ( ) ) {
return ;
}
# endif
/*
* Set the single - step flag . This will cause the debugger ( if present )
* to break to the console within the AML debugger at the start of the
* next AML instruction .
*/
acpi_gbl_cm_single_step = TRUE ;
acpi_os_printf ( " **break** Executed AML BreakPoint opcode \n " ) ;
}
2018-11-05 20:43:51 +03:00
# ifdef ACPI_DISASSEMBLER
/*******************************************************************************
*
* FUNCTION : acpi_db_get_display_op
*
* PARAMETERS : walk_state - Current walk
* op - Current executing op ( from aml interpreter )
*
* RETURN : Opcode to display
*
* DESCRIPTION : Find the opcode to display during single stepping
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static union acpi_parse_object * acpi_db_get_display_op ( struct acpi_walk_state
* walk_state ,
union acpi_parse_object
* op )
{
union acpi_parse_object * display_op ;
union acpi_parse_object * parent_op ;
display_op = op ;
parent_op = op - > common . parent ;
if ( parent_op ) {
if ( ( walk_state - > control_state ) & &
( walk_state - > control_state - > common . state = =
ACPI_CONTROL_PREDICATE_EXECUTING ) ) {
/*
* We are executing the predicate of an IF or WHILE statement
* Search upwards for the containing IF or WHILE so that the
* entire predicate can be displayed .
*/
while ( parent_op ) {
if ( ( parent_op - > common . aml_opcode = = AML_IF_OP )
| | ( parent_op - > common . aml_opcode = =
AML_WHILE_OP ) ) {
display_op = parent_op ;
break ;
}
parent_op = parent_op - > common . parent ;
}
} else {
while ( parent_op ) {
if ( ( parent_op - > common . aml_opcode = = AML_IF_OP )
| | ( parent_op - > common . aml_opcode = =
AML_ELSE_OP )
| | ( parent_op - > common . aml_opcode = =
AML_SCOPE_OP )
| | ( parent_op - > common . aml_opcode = =
AML_METHOD_OP )
| | ( parent_op - > common . aml_opcode = =
AML_WHILE_OP ) ) {
break ;
}
display_op = parent_op ;
parent_op = parent_op - > common . parent ;
}
}
}
return display_op ;
}
# endif
2015-10-19 05:25:20 +03:00
/*******************************************************************************
*
* FUNCTION : acpi_db_single_step
*
* PARAMETERS : walk_state - Current walk
* op - Current executing op ( from aml interpreter )
* opcode_class - Class of the current AML Opcode
*
* RETURN : Status
*
* DESCRIPTION : Called just before execution of an AML opcode .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2016-05-05 07:57:53 +03:00
acpi_db_single_step ( struct acpi_walk_state * walk_state ,
union acpi_parse_object * op , u32 opcode_class )
2015-10-19 05:25:20 +03:00
{
union acpi_parse_object * next ;
acpi_status status = AE_OK ;
u32 original_debug_level ;
u32 aml_offset ;
ACPI_FUNCTION_ENTRY ( ) ;
2015-10-19 05:25:50 +03:00
# ifndef ACPI_APPLICATION
if ( acpi_gbl_db_thread_id ! = acpi_os_get_thread_id ( ) ) {
return ( AE_OK ) ;
}
# endif
2015-10-19 05:25:20 +03:00
/* Check the abort flag */
if ( acpi_gbl_abort_method ) {
acpi_gbl_abort_method = FALSE ;
return ( AE_ABORT_METHOD ) ;
}
aml_offset = ( u32 ) ACPI_PTR_DIFF ( op - > common . aml ,
walk_state - > parser_state . aml_start ) ;
/* Check for single-step breakpoint */
if ( walk_state - > method_breakpoint & &
( walk_state - > method_breakpoint < = aml_offset ) ) {
/* Check if the breakpoint has been reached or passed */
/* Hit the breakpoint, resume single step, reset breakpoint */
acpi_os_printf ( " ***Break*** at AML offset %X \n " , aml_offset ) ;
acpi_gbl_cm_single_step = TRUE ;
acpi_gbl_step_to_next_call = FALSE ;
walk_state - > method_breakpoint = 0 ;
}
/* Check for user breakpoint (Must be on exact Aml offset) */
else if ( walk_state - > user_breakpoint & &
( walk_state - > user_breakpoint = = aml_offset ) ) {
acpi_os_printf ( " ***UserBreakpoint*** at AML offset %X \n " ,
aml_offset ) ;
acpi_gbl_cm_single_step = TRUE ;
acpi_gbl_step_to_next_call = FALSE ;
walk_state - > method_breakpoint = 0 ;
}
/*
* Check if this is an opcode that we are interested in - -
* namely , opcodes that have arguments
*/
if ( op - > common . aml_opcode = = AML_INT_NAMEDFIELD_OP ) {
return ( AE_OK ) ;
}
switch ( opcode_class ) {
case AML_CLASS_UNKNOWN :
case AML_CLASS_ARGUMENT : /* constants, literals, etc. do nothing */
return ( AE_OK ) ;
default :
/* All other opcodes -- continue */
break ;
}
/*
* Under certain debug conditions , display this opcode and its operands
*/
if ( ( acpi_gbl_db_output_to_file ) | |
( acpi_gbl_cm_single_step ) | | ( acpi_dbg_level & ACPI_LV_PARSE ) ) {
if ( ( acpi_gbl_db_output_to_file ) | |
( acpi_dbg_level & ACPI_LV_PARSE ) ) {
acpi_os_printf
2017-06-05 11:42:28 +03:00
( " \n AML Debug: Next AML Opcode to execute: \n " ) ;
2015-10-19 05:25:20 +03:00
}
/*
* Display this op ( and only this op - zero out the NEXT field
* temporarily , and disable parser trace output for the duration of
* the display because we don ' t want the extraneous debug output )
*/
original_debug_level = acpi_dbg_level ;
acpi_dbg_level & = ~ ( ACPI_LV_PARSE | ACPI_LV_FUNCTIONS ) ;
next = op - > common . next ;
op - > common . next = NULL ;
2018-08-11 00:42:59 +03:00
/* Now we can disassemble and display it */
2015-10-19 05:25:20 +03:00
# ifdef ACPI_DISASSEMBLER
2018-11-05 20:43:51 +03:00
acpi_dm_disassemble ( walk_state ,
acpi_db_get_display_op ( walk_state , op ) ,
ACPI_UINT32_MAX ) ;
2018-08-11 00:42:59 +03:00
# else
/*
* The AML Disassembler is not configured - at least we can
* display the opcode value and name
*/
acpi_os_printf ( " AML Opcode: %4.4X %s \n " , op - > common . aml_opcode ,
acpi_ps_get_opcode_name ( op - > common . aml_opcode ) ) ;
2015-10-19 05:25:20 +03:00
# endif
if ( ( op - > common . aml_opcode = = AML_IF_OP ) | |
( op - > common . aml_opcode = = AML_WHILE_OP ) ) {
if ( walk_state - > control_state - > common . value ) {
acpi_os_printf
( " Predicate = [True], IF block was executed \n " ) ;
} else {
acpi_os_printf
( " Predicate = [False], Skipping IF block \n " ) ;
}
} else if ( op - > common . aml_opcode = = AML_ELSE_OP ) {
acpi_os_printf
( " Predicate = [False], ELSE block was executed \n " ) ;
}
/* Restore everything */
op - > common . next = next ;
acpi_os_printf ( " \n " ) ;
if ( ( acpi_gbl_db_output_to_file ) | |
( acpi_dbg_level & ACPI_LV_PARSE ) ) {
acpi_os_printf ( " \n " ) ;
}
acpi_dbg_level = original_debug_level ;
}
/* If we are not single stepping, just continue executing the method */
if ( ! acpi_gbl_cm_single_step ) {
return ( AE_OK ) ;
}
/*
* If we are executing a step - to - call command ,
* Check if this is a method call .
*/
if ( acpi_gbl_step_to_next_call ) {
if ( op - > common . aml_opcode ! = AML_INT_METHODCALL_OP ) {
/* Not a method call, just keep executing */
return ( AE_OK ) ;
}
/* Found a method call, stop executing */
acpi_gbl_step_to_next_call = FALSE ;
}
/*
* If the next opcode is a method call , we will " step over " it
* by default .
*/
if ( op - > common . aml_opcode = = AML_INT_METHODCALL_OP ) {
/* Force no more single stepping while executing called method */
acpi_gbl_cm_single_step = FALSE ;
/*
* Set the breakpoint on / before the call , it will stop execution
* as soon as we return
*/
walk_state - > method_breakpoint = 1 ; /* Must be non-zero! */
}
2017-04-26 11:18:33 +03:00
acpi_ex_exit_interpreter ( ) ;
2015-10-19 05:25:20 +03:00
status = acpi_db_start_command ( walk_state , op ) ;
2017-04-26 11:18:33 +03:00
acpi_ex_enter_interpreter ( ) ;
2015-10-19 05:25:20 +03:00
/* User commands complete, continue execution of the interrupted method */
return ( status ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_initialize_debugger
*
* PARAMETERS : None
*
* RETURN : Status
*
* DESCRIPTION : Init and start debugger
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status acpi_initialize_debugger ( void )
{
acpi_status status ;
ACPI_FUNCTION_TRACE ( acpi_initialize_debugger ) ;
/* Init globals */
acpi_gbl_db_buffer = NULL ;
acpi_gbl_db_filename = NULL ;
acpi_gbl_db_output_to_file = FALSE ;
acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2 ;
acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES ;
acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT ;
acpi_gbl_db_opt_no_ini_methods = FALSE ;
acpi_gbl_db_buffer = acpi_os_allocate ( ACPI_DEBUG_BUFFER_SIZE ) ;
if ( ! acpi_gbl_db_buffer ) {
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
}
memset ( acpi_gbl_db_buffer , 0 , ACPI_DEBUG_BUFFER_SIZE ) ;
/* Initial scope is the root */
acpi_gbl_db_scope_buf [ 0 ] = AML_ROOT_PREFIX ;
acpi_gbl_db_scope_buf [ 1 ] = 0 ;
acpi_gbl_db_scope_node = acpi_gbl_root_node ;
2015-10-19 05:25:32 +03:00
/* Initialize user commands loop */
acpi_gbl_db_terminate_loop = FALSE ;
2015-10-19 05:25:20 +03:00
/*
* If configured for multi - thread support , the debug executor runs in
* a separate thread so that the front end can be in another address
* space , environment , or even another machine .
*/
if ( acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED ) {
/* These were created with one unit, grab it */
2016-12-28 10:28:07 +03:00
status = acpi_os_initialize_debugger ( ) ;
2015-10-19 05:25:20 +03:00
if ( ACPI_FAILURE ( status ) ) {
acpi_os_printf ( " Could not get debugger mutex \n " ) ;
return_ACPI_STATUS ( status ) ;
}
/* Create the debug execution thread to execute commands */
2015-10-19 05:25:32 +03:00
acpi_gbl_db_threads_terminated = FALSE ;
2015-10-19 05:25:50 +03:00
status = acpi_os_execute ( OSL_DEBUGGER_MAIN_THREAD ,
2015-10-19 05:25:20 +03:00
acpi_db_execute_thread , NULL ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_EXCEPTION ( ( AE_INFO , status ,
" Could not start debugger thread " ) ) ;
2015-10-19 05:25:32 +03:00
acpi_gbl_db_threads_terminated = TRUE ;
2015-10-19 05:25:20 +03:00
return_ACPI_STATUS ( status ) ;
}
2015-10-19 05:25:50 +03:00
} else {
acpi_gbl_db_thread_id = acpi_os_get_thread_id ( ) ;
2015-10-19 05:25:20 +03:00
}
return_ACPI_STATUS ( AE_OK ) ;
}
ACPI_EXPORT_SYMBOL ( acpi_initialize_debugger )
/*******************************************************************************
*
* FUNCTION : acpi_terminate_debugger
*
* PARAMETERS : None
*
* RETURN : None
*
* DESCRIPTION : Stop debugger
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void acpi_terminate_debugger ( void )
{
2015-10-19 05:25:32 +03:00
/* Terminate the AML Debugger */
acpi_gbl_db_terminate_loop = TRUE ;
if ( acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED ) {
/* Wait the AML Debugger threads */
while ( ! acpi_gbl_db_threads_terminated ) {
acpi_os_sleep ( 100 ) ;
}
2015-12-03 05:42:46 +03:00
2016-12-28 10:28:07 +03:00
acpi_os_terminate_debugger ( ) ;
2015-10-19 05:25:32 +03:00
}
2015-10-19 05:25:20 +03:00
if ( acpi_gbl_db_buffer ) {
acpi_os_free ( acpi_gbl_db_buffer ) ;
acpi_gbl_db_buffer = NULL ;
}
/* Ensure that debug output is now disabled */
acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT ;
}
ACPI_EXPORT_SYMBOL ( acpi_terminate_debugger )
2015-10-19 05:25:50 +03:00
/*******************************************************************************
*
* FUNCTION : acpi_set_debugger_thread_id
*
* PARAMETERS : thread_id - Debugger thread ID
*
* RETURN : None
*
* DESCRIPTION : Set debugger thread ID
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void acpi_set_debugger_thread_id ( acpi_thread_id thread_id )
{
acpi_gbl_db_thread_id = thread_id ;
}
ACPI_EXPORT_SYMBOL ( acpi_set_debugger_thread_id )