|  | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 | 
|  | /****************************************************************************** | 
|  | * | 
|  | * Module Name: dsdebug - Parser/Interpreter interface - debugging | 
|  | * | 
|  | * Copyright (C) 2000 - 2020, 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 |