brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · 9dfd693 Raw
523 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: dbxface - AML Debugger external interfaces5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "amlcode.h"11#include "acdebug.h"12#include "acinterp.h"13#include "acparser.h"14 15#define _COMPONENT          ACPI_CA_DEBUGGER16ACPI_MODULE_NAME("dbxface")17 18/* Local prototypes */19static acpi_status20acpi_db_start_command(struct acpi_walk_state *walk_state,21		      union acpi_parse_object *op);22 23#ifdef ACPI_OBSOLETE_FUNCTIONS24void acpi_db_method_end(struct acpi_walk_state *walk_state);25#endif26 27#ifdef ACPI_DISASSEMBLER28static union acpi_parse_object *acpi_db_get_display_op(struct acpi_walk_state29						       *walk_state,30						       union acpi_parse_object31						       *op);32#endif33 34/*******************************************************************************35 *36 * FUNCTION:    acpi_db_start_command37 *38 * PARAMETERS:  walk_state      - Current walk39 *              op              - Current executing Op, from AML interpreter40 *41 * RETURN:      Status42 *43 * DESCRIPTION: Enter debugger command loop44 *45 ******************************************************************************/46 47static acpi_status48acpi_db_start_command(struct acpi_walk_state *walk_state,49		      union acpi_parse_object *op)50{51	acpi_status status;52 53	/* TBD: [Investigate] are there namespace locking issues here? */54 55	/* acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */56 57	/* Go into the command loop and await next user command */58 59	acpi_gbl_method_executing = TRUE;60	status = AE_CTRL_TRUE;61 62	while (status == AE_CTRL_TRUE) {63 64		/* Notify the completion of the command */65 66		status = acpi_os_notify_command_complete();67		if (ACPI_FAILURE(status)) {68			goto error_exit;69		}70 71		/* Wait the readiness of the command */72 73		status = acpi_os_wait_command_ready();74		if (ACPI_FAILURE(status)) {75			goto error_exit;76		}77 78		status =79		    acpi_db_command_dispatch(acpi_gbl_db_line_buf, walk_state,80					     op);81	}82 83	/* acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */84 85error_exit:86	if (ACPI_FAILURE(status) && status != AE_CTRL_TERMINATE) {87		ACPI_EXCEPTION((AE_INFO, status,88				"While parsing/handling command line"));89	}90	return (status);91}92 93/*******************************************************************************94 *95 * FUNCTION:    acpi_db_signal_break_point96 *97 * PARAMETERS:  walk_state      - Current walk98 *99 * RETURN:      Status100 *101 * DESCRIPTION: Called for AML_BREAKPOINT_OP102 *103 ******************************************************************************/104 105void acpi_db_signal_break_point(struct acpi_walk_state *walk_state)106{107 108#ifndef ACPI_APPLICATION109	if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {110		return;111	}112#endif113 114	/*115	 * Set the single-step flag. This will cause the debugger (if present)116	 * to break to the console within the AML debugger at the start of the117	 * next AML instruction.118	 */119	acpi_gbl_cm_single_step = TRUE;120	acpi_os_printf("**break** Executed AML BreakPoint opcode\n");121}122 123#ifdef ACPI_DISASSEMBLER124/*******************************************************************************125 *126 * FUNCTION:    acpi_db_get_display_op127 *128 * PARAMETERS:  walk_state      - Current walk129 *              op              - Current executing op (from aml interpreter)130 *131 * RETURN:      Opcode to display132 *133 * DESCRIPTION: Find the opcode to display during single stepping134 *135 ******************************************************************************/136 137static union acpi_parse_object *acpi_db_get_display_op(struct acpi_walk_state138						       *walk_state,139						       union acpi_parse_object140						       *op)141{142	union acpi_parse_object *display_op;143	union acpi_parse_object *parent_op;144 145	display_op = op;146	parent_op = op->common.parent;147	if (parent_op) {148		if ((walk_state->control_state) &&149		    (walk_state->control_state->common.state ==150		     ACPI_CONTROL_PREDICATE_EXECUTING)) {151			/*152			 * We are executing the predicate of an IF or WHILE statement153			 * Search upwards for the containing IF or WHILE so that the154			 * entire predicate can be displayed.155			 */156			while (parent_op) {157				if ((parent_op->common.aml_opcode == AML_IF_OP)158				    || (parent_op->common.aml_opcode ==159					AML_WHILE_OP)) {160					display_op = parent_op;161					break;162				}163				parent_op = parent_op->common.parent;164			}165		} else {166			while (parent_op) {167				if ((parent_op->common.aml_opcode == AML_IF_OP)168				    || (parent_op->common.aml_opcode ==169					AML_ELSE_OP)170				    || (parent_op->common.aml_opcode ==171					AML_SCOPE_OP)172				    || (parent_op->common.aml_opcode ==173					AML_METHOD_OP)174				    || (parent_op->common.aml_opcode ==175					AML_WHILE_OP)) {176					break;177				}178				display_op = parent_op;179				parent_op = parent_op->common.parent;180			}181		}182	}183	return display_op;184}185#endif186 187/*******************************************************************************188 *189 * FUNCTION:    acpi_db_single_step190 *191 * PARAMETERS:  walk_state      - Current walk192 *              op              - Current executing op (from aml interpreter)193 *              opcode_class    - Class of the current AML Opcode194 *195 * RETURN:      Status196 *197 * DESCRIPTION: Called just before execution of an AML opcode.198 *199 ******************************************************************************/200 201acpi_status202acpi_db_single_step(struct acpi_walk_state *walk_state,203		    union acpi_parse_object *op, u32 opcode_class)204{205	union acpi_parse_object *next;206	acpi_status status = AE_OK;207	u32 original_debug_level;208	u32 aml_offset;209 210	ACPI_FUNCTION_ENTRY();211 212#ifndef ACPI_APPLICATION213	if (acpi_gbl_db_thread_id != acpi_os_get_thread_id()) {214		return (AE_OK);215	}216#endif217 218	/* Check the abort flag */219 220	if (acpi_gbl_abort_method) {221		acpi_gbl_abort_method = FALSE;222		return (AE_ABORT_METHOD);223	}224 225	aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml,226					walk_state->parser_state.aml_start);227 228	/* Check for single-step breakpoint */229 230	if (walk_state->method_breakpoint &&231	    (walk_state->method_breakpoint <= aml_offset)) {232 233		/* Check if the breakpoint has been reached or passed */234		/* Hit the breakpoint, resume single step, reset breakpoint */235 236		acpi_os_printf("***Break*** at AML offset %X\n", aml_offset);237		acpi_gbl_cm_single_step = TRUE;238		acpi_gbl_step_to_next_call = FALSE;239		walk_state->method_breakpoint = 0;240	}241 242	/* Check for user breakpoint (Must be on exact Aml offset) */243 244	else if (walk_state->user_breakpoint &&245		 (walk_state->user_breakpoint == aml_offset)) {246		acpi_os_printf("***UserBreakpoint*** at AML offset %X\n",247			       aml_offset);248		acpi_gbl_cm_single_step = TRUE;249		acpi_gbl_step_to_next_call = FALSE;250		walk_state->method_breakpoint = 0;251	}252 253	/*254	 * Check if this is an opcode that we are interested in --255	 * namely, opcodes that have arguments256	 */257	if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {258		return (AE_OK);259	}260 261	switch (opcode_class) {262	case AML_CLASS_UNKNOWN:263	case AML_CLASS_ARGUMENT:	/* constants, literals, etc. do nothing */264 265		return (AE_OK);266 267	default:268 269		/* All other opcodes -- continue */270		break;271	}272 273	/*274	 * Under certain debug conditions, display this opcode and its operands275	 */276	if ((acpi_gbl_db_output_to_file) ||277	    (acpi_gbl_cm_single_step) || (acpi_dbg_level & ACPI_LV_PARSE)) {278		if ((acpi_gbl_db_output_to_file) ||279		    (acpi_dbg_level & ACPI_LV_PARSE)) {280			acpi_os_printf281			    ("\nAML Debug: Next AML Opcode to execute:\n");282		}283 284		/*285		 * Display this op (and only this op - zero out the NEXT field286		 * temporarily, and disable parser trace output for the duration of287		 * the display because we don't want the extraneous debug output)288		 */289		original_debug_level = acpi_dbg_level;290		acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);291		next = op->common.next;292		op->common.next = NULL;293 294		/* Now we can disassemble and display it */295 296#ifdef ACPI_DISASSEMBLER297		acpi_dm_disassemble(walk_state,298				    acpi_db_get_display_op(walk_state, op),299				    ACPI_UINT32_MAX);300#else301		/*302		 * The AML Disassembler is not configured - at least we can303		 * display the opcode value and name304		 */305		acpi_os_printf("AML Opcode: %4.4X %s\n", op->common.aml_opcode,306			       acpi_ps_get_opcode_name(op->common.aml_opcode));307#endif308 309		if ((op->common.aml_opcode == AML_IF_OP) ||310		    (op->common.aml_opcode == AML_WHILE_OP)) {311			if (walk_state->control_state->common.value) {312				acpi_os_printf313				    ("Predicate = [True], IF block was executed\n");314			} else {315				acpi_os_printf316				    ("Predicate = [False], Skipping IF block\n");317			}318		} else if (op->common.aml_opcode == AML_ELSE_OP) {319			acpi_os_printf320			    ("Predicate = [False], ELSE block was executed\n");321		}322 323		/* Restore everything */324 325		op->common.next = next;326		acpi_os_printf("\n");327		if ((acpi_gbl_db_output_to_file) ||328		    (acpi_dbg_level & ACPI_LV_PARSE)) {329			acpi_os_printf("\n");330		}331		acpi_dbg_level = original_debug_level;332	}333 334	/* If we are not single stepping, just continue executing the method */335 336	if (!acpi_gbl_cm_single_step) {337		return (AE_OK);338	}339 340	/*341	 * If we are executing a step-to-call command,342	 * Check if this is a method call.343	 */344	if (acpi_gbl_step_to_next_call) {345		if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {346 347			/* Not a method call, just keep executing */348 349			return (AE_OK);350		}351 352		/* Found a method call, stop executing */353 354		acpi_gbl_step_to_next_call = FALSE;355	}356 357	/*358	 * If the next opcode is a method call, we will "step over" it359	 * by default.360	 */361	if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {362 363		/* Force no more single stepping while executing called method */364 365		acpi_gbl_cm_single_step = FALSE;366 367		/*368		 * Set the breakpoint on/before the call, it will stop execution369		 * as soon as we return370		 */371		walk_state->method_breakpoint = 1;	/* Must be non-zero! */372	}373 374	acpi_ex_exit_interpreter();375	status = acpi_db_start_command(walk_state, op);376	acpi_ex_enter_interpreter();377 378	/* User commands complete, continue execution of the interrupted method */379 380	return (status);381}382 383/*******************************************************************************384 *385 * FUNCTION:    acpi_initialize_debugger386 *387 * PARAMETERS:  None388 *389 * RETURN:      Status390 *391 * DESCRIPTION: Init and start debugger392 *393 ******************************************************************************/394 395acpi_status acpi_initialize_debugger(void)396{397	acpi_status status;398 399	ACPI_FUNCTION_TRACE(acpi_initialize_debugger);400 401	/* Init globals */402 403	acpi_gbl_db_buffer = NULL;404	acpi_gbl_db_filename = NULL;405	acpi_gbl_db_output_to_file = FALSE;406 407	acpi_gbl_db_debug_level = ACPI_LV_VERBOSITY2;408	acpi_gbl_db_console_debug_level = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;409	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;410 411	acpi_gbl_db_opt_no_ini_methods = FALSE;412	acpi_gbl_db_opt_no_region_support = FALSE;413 414	acpi_gbl_db_buffer = acpi_os_allocate(ACPI_DEBUG_BUFFER_SIZE);415	if (!acpi_gbl_db_buffer) {416		return_ACPI_STATUS(AE_NO_MEMORY);417	}418	memset(acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);419 420	/* Initial scope is the root */421 422	acpi_gbl_db_scope_buf[0] = AML_ROOT_PREFIX;423	acpi_gbl_db_scope_buf[1] = 0;424	acpi_gbl_db_scope_node = acpi_gbl_root_node;425 426	/* Initialize user commands loop */427 428	acpi_gbl_db_terminate_loop = FALSE;429 430	/*431	 * If configured for multi-thread support, the debug executor runs in432	 * a separate thread so that the front end can be in another address433	 * space, environment, or even another machine.434	 */435	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {436 437		/* These were created with one unit, grab it */438 439		status = acpi_os_initialize_debugger();440		if (ACPI_FAILURE(status)) {441			acpi_os_printf("Could not get debugger mutex\n");442			return_ACPI_STATUS(status);443		}444 445		/* Create the debug execution thread to execute commands */446 447		acpi_gbl_db_threads_terminated = FALSE;448		status = acpi_os_execute(OSL_DEBUGGER_MAIN_THREAD,449					 acpi_db_execute_thread, NULL);450		if (ACPI_FAILURE(status)) {451			ACPI_EXCEPTION((AE_INFO, status,452					"Could not start debugger thread"));453			acpi_gbl_db_threads_terminated = TRUE;454			return_ACPI_STATUS(status);455		}456	} else {457		acpi_gbl_db_thread_id = acpi_os_get_thread_id();458	}459 460	return_ACPI_STATUS(AE_OK);461}462 463ACPI_EXPORT_SYMBOL(acpi_initialize_debugger)464 465/*******************************************************************************466 *467 * FUNCTION:    acpi_terminate_debugger468 *469 * PARAMETERS:  None470 *471 * RETURN:      None472 *473 * DESCRIPTION: Stop debugger474 *475 ******************************************************************************/476void acpi_terminate_debugger(void)477{478 479	/* Terminate the AML Debugger */480 481	acpi_gbl_db_terminate_loop = TRUE;482 483	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {484 485		/* Wait the AML Debugger threads */486 487		while (!acpi_gbl_db_threads_terminated) {488			acpi_os_sleep(100);489		}490 491		acpi_os_terminate_debugger();492	}493 494	if (acpi_gbl_db_buffer) {495		acpi_os_free(acpi_gbl_db_buffer);496		acpi_gbl_db_buffer = NULL;497	}498 499	/* Ensure that debug output is now disabled */500 501	acpi_gbl_db_output_flags = ACPI_DB_DISABLE_OUTPUT;502}503 504ACPI_EXPORT_SYMBOL(acpi_terminate_debugger)505 506/*******************************************************************************507 *508 * FUNCTION:    acpi_set_debugger_thread_id509 *510 * PARAMETERS:  thread_id       - Debugger thread ID511 *512 * RETURN:      None513 *514 * DESCRIPTION: Set debugger thread ID515 *516 ******************************************************************************/517void acpi_set_debugger_thread_id(acpi_thread_id thread_id)518{519	acpi_gbl_db_thread_id = thread_id;520}521 522ACPI_EXPORT_SYMBOL(acpi_set_debugger_thread_id)523