| // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 | 
 | /****************************************************************************** | 
 |  * | 
 |  * Module Name: dsdebug - Parser/Interpreter interface - debugging | 
 |  * | 
 |  * Copyright (C) 2000 - 2018, Intel Corp. | 
 |  * | 
 |  *****************************************************************************/ | 
 |  | 
 | #include <acpi/acpi.h> | 
 | #include "accommon.h" | 
 | #include "acdispat.h" | 
 | #include "acnamesp.h" | 
 | #ifdef ACPI_DISASSEMBLER | 
 | #include "acdisasm.h" | 
 | #endif | 
 | #include "acinterp.h" | 
 |  | 
 | #define _COMPONENT          ACPI_DISPATCHER | 
 | ACPI_MODULE_NAME("dsdebug") | 
 |  | 
 | #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) | 
 | /* Local prototypes */ | 
 | static void | 
 | acpi_ds_print_node_pathname(struct acpi_namespace_node *node, | 
 | 			    const char *message); | 
 |  | 
 | /******************************************************************************* | 
 |  * | 
 |  * FUNCTION:    acpi_ds_print_node_pathname | 
 |  * | 
 |  * PARAMETERS:  node            - Object | 
 |  *              message         - Prefix message | 
 |  * | 
 |  * DESCRIPTION: Print an object's full namespace pathname | 
 |  *              Manages allocation/freeing of a pathname buffer | 
 |  * | 
 |  ******************************************************************************/ | 
 |  | 
 | static void | 
 | acpi_ds_print_node_pathname(struct acpi_namespace_node *node, | 
 | 			    const char *message) | 
 | { | 
 | 	struct acpi_buffer buffer; | 
 | 	acpi_status status; | 
 |  | 
 | 	ACPI_FUNCTION_TRACE(ds_print_node_pathname); | 
 |  | 
 | 	if (!node) { | 
 | 		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]")); | 
 | 		return_VOID; | 
 | 	} | 
 |  | 
 | 	/* Convert handle to full pathname and print it (with supplied message) */ | 
 |  | 
 | 	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; | 
 |  | 
 | 	status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); | 
 | 	if (ACPI_SUCCESS(status)) { | 
 | 		if (message) { | 
 | 			ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ", | 
 | 					      message)); | 
 | 		} | 
 |  | 
 | 		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)", | 
 | 				      (char *)buffer.pointer, node)); | 
 | 		ACPI_FREE(buffer.pointer); | 
 | 	} | 
 |  | 
 | 	return_VOID; | 
 | } | 
 |  | 
 | /******************************************************************************* | 
 |  * | 
 |  * FUNCTION:    acpi_ds_dump_method_stack | 
 |  * | 
 |  * PARAMETERS:  status          - Method execution status | 
 |  *              walk_state      - Current state of the parse tree walk | 
 |  *              op              - Executing parse op | 
 |  * | 
 |  * RETURN:      None | 
 |  * | 
 |  * DESCRIPTION: Called when a method has been aborted because of an error. | 
 |  *              Dumps the method execution stack. | 
 |  * | 
 |  ******************************************************************************/ | 
 |  | 
 | void | 
 | acpi_ds_dump_method_stack(acpi_status status, | 
 | 			  struct acpi_walk_state *walk_state, | 
 | 			  union acpi_parse_object *op) | 
 | { | 
 | 	union acpi_parse_object *next; | 
 | 	struct acpi_thread_state *thread; | 
 | 	struct acpi_walk_state *next_walk_state; | 
 | 	struct acpi_namespace_node *previous_method = NULL; | 
 | 	union acpi_operand_object *method_desc; | 
 |  | 
 | 	ACPI_FUNCTION_TRACE(ds_dump_method_stack); | 
 |  | 
 | 	/* Ignore control codes, they are not errors */ | 
 |  | 
 | 	if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) { | 
 | 		return_VOID; | 
 | 	} | 
 |  | 
 | 	/* We may be executing a deferred opcode */ | 
 |  | 
 | 	if (walk_state->deferred_node) { | 
 | 		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 
 | 				  "Executing subtree for Buffer/Package/Region\n")); | 
 | 		return_VOID; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * If there is no Thread, we are not actually executing a method. | 
 | 	 * This can happen when the iASL compiler calls the interpreter | 
 | 	 * to perform constant folding. | 
 | 	 */ | 
 | 	thread = walk_state->thread; | 
 | 	if (!thread) { | 
 | 		return_VOID; | 
 | 	} | 
 |  | 
 | 	/* Display exception and method name */ | 
 |  | 
 | 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 
 | 			  "\n**** Exception %s during execution of method ", | 
 | 			  acpi_format_exception(status))); | 
 |  | 
 | 	acpi_ds_print_node_pathname(walk_state->method_node, NULL); | 
 |  | 
 | 	/* Display stack of executing methods */ | 
 |  | 
 | 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, | 
 | 			      "\n\nMethod Execution Stack:\n")); | 
 | 	next_walk_state = thread->walk_state_list; | 
 |  | 
 | 	/* Walk list of linked walk states */ | 
 |  | 
 | 	while (next_walk_state) { | 
 | 		method_desc = next_walk_state->method_desc; | 
 | 		if (method_desc) { | 
 | 			acpi_ex_stop_trace_method((struct acpi_namespace_node *) | 
 | 						  method_desc->method.node, | 
 | 						  method_desc, walk_state); | 
 | 		} | 
 |  | 
 | 		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 
 | 				  "    Method [%4.4s] executing: ", | 
 | 				  acpi_ut_get_node_name(next_walk_state-> | 
 | 							method_node))); | 
 |  | 
 | 		/* First method is the currently executing method */ | 
 |  | 
 | 		if (next_walk_state == walk_state) { | 
 | 			if (op) { | 
 |  | 
 | 				/* Display currently executing ASL statement */ | 
 |  | 
 | 				next = op->common.next; | 
 | 				op->common.next = NULL; | 
 |  | 
 | #ifdef ACPI_DISASSEMBLER | 
 | 				if (walk_state->method_node != | 
 | 				    acpi_gbl_root_node) { | 
 |  | 
 | 					/* More verbose if not module-level code */ | 
 |  | 
 | 					acpi_os_printf("Failed at "); | 
 | 					acpi_dm_disassemble(next_walk_state, op, | 
 | 							    ACPI_UINT32_MAX); | 
 | 				} | 
 | #endif | 
 | 				op->common.next = next; | 
 | 			} | 
 | 		} else { | 
 | 			/* | 
 | 			 * This method has called another method | 
 | 			 * NOTE: the method call parse subtree is already deleted at | 
 | 			 * this point, so we cannot disassemble the method invocation. | 
 | 			 */ | 
 | 			ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, | 
 | 					      "Call to method ")); | 
 | 			acpi_ds_print_node_pathname(previous_method, NULL); | 
 | 		} | 
 |  | 
 | 		previous_method = next_walk_state->method_node; | 
 | 		next_walk_state = next_walk_state->next; | 
 | 		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n")); | 
 | 	} | 
 |  | 
 | 	return_VOID; | 
 | } | 
 |  | 
 | #else | 
 | void | 
 | acpi_ds_dump_method_stack(acpi_status status, | 
 | 			  struct acpi_walk_state *walk_state, | 
 | 			  union acpi_parse_object *op) | 
 | { | 
 | 	return; | 
 | } | 
 |  | 
 | #endif |