1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: dsdebug - Parser/Interpreter interface - debugging
5 *
6 * Copyright (C) 2000 - 2023, Intel Corp.
7 *
8 *****************************************************************************/
9
10#include <acpi/acpi.h>
11#include "accommon.h"
12#include "acdispat.h"
13#include "acnamesp.h"
14#ifdef ACPI_DISASSEMBLER
15#include "acdisasm.h"
16#endif
17#include "acinterp.h"
18
19#define _COMPONENT          ACPI_DISPATCHER
20ACPI_MODULE_NAME("dsdebug")
21
22#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
23/* Local prototypes */
24static void
25acpi_ds_print_node_pathname(struct acpi_namespace_node *node,
26			    const char *message);
27
28/*******************************************************************************
29 *
30 * FUNCTION:    acpi_ds_print_node_pathname
31 *
32 * PARAMETERS:  node            - Object
33 *              message         - Prefix message
34 *
35 * DESCRIPTION: Print an object's full namespace pathname
36 *              Manages allocation/freeing of a pathname buffer
37 *
38 ******************************************************************************/
39
40static void
41acpi_ds_print_node_pathname(struct acpi_namespace_node *node,
42			    const char *message)
43{
44	struct acpi_buffer buffer;
45	acpi_status status;
46
47	ACPI_FUNCTION_TRACE(ds_print_node_pathname);
48
49	if (!node) {
50		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]"));
51		return_VOID;
52	}
53
54	/* Convert handle to full pathname and print it (with supplied message) */
55
56	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
57
58	status = acpi_ns_handle_to_pathname(node, &buffer, TRUE);
59	if (ACPI_SUCCESS(status)) {
60		if (message) {
61			ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ",
62					      message));
63		}
64
65		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)",
66				      (char *)buffer.pointer, node));
67		ACPI_FREE(buffer.pointer);
68	}
69
70	return_VOID;
71}
72
73/*******************************************************************************
74 *
75 * FUNCTION:    acpi_ds_dump_method_stack
76 *
77 * PARAMETERS:  status          - Method execution status
78 *              walk_state      - Current state of the parse tree walk
79 *              op              - Executing parse op
80 *
81 * RETURN:      None
82 *
83 * DESCRIPTION: Called when a method has been aborted because of an error.
84 *              Dumps the method execution stack.
85 *
86 ******************************************************************************/
87
88void
89acpi_ds_dump_method_stack(acpi_status status,
90			  struct acpi_walk_state *walk_state,
91			  union acpi_parse_object *op)
92{
93	union acpi_parse_object *next;
94	struct acpi_thread_state *thread;
95	struct acpi_walk_state *next_walk_state;
96	struct acpi_namespace_node *previous_method = NULL;
97	union acpi_operand_object *method_desc;
98
99	ACPI_FUNCTION_TRACE(ds_dump_method_stack);
100
101	/* Ignore control codes, they are not errors */
102
103	if (ACPI_CNTL_EXCEPTION(status)) {
104		return_VOID;
105	}
106
107	/* We may be executing a deferred opcode */
108
109	if (walk_state->deferred_node) {
110		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
111				  "Executing subtree for Buffer/Package/Region\n"));
112		return_VOID;
113	}
114
115	/*
116	 * If there is no Thread, we are not actually executing a method.
117	 * This can happen when the iASL compiler calls the interpreter
118	 * to perform constant folding.
119	 */
120	thread = walk_state->thread;
121	if (!thread) {
122		return_VOID;
123	}
124
125	/* Display exception and method name */
126
127	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
128			  "\n**** Exception %s during execution of method ",
129			  acpi_format_exception(status)));
130
131	acpi_ds_print_node_pathname(walk_state->method_node, NULL);
132
133	/* Display stack of executing methods */
134
135	ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH,
136			      "\n\nMethod Execution Stack:\n"));
137	next_walk_state = thread->walk_state_list;
138
139	/* Walk list of linked walk states */
140
141	while (next_walk_state) {
142		method_desc = next_walk_state->method_desc;
143		if (method_desc) {
144			acpi_ex_stop_trace_method((struct acpi_namespace_node *)
145						  method_desc->method.node,
146						  method_desc, walk_state);
147		}
148
149		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
150				  "    Method [%4.4s] executing: ",
151				  acpi_ut_get_node_name(next_walk_state->
152							method_node)));
153
154		/* First method is the currently executing method */
155
156		if (next_walk_state == walk_state) {
157			if (op) {
158
159				/* Display currently executing ASL statement */
160
161				next = op->common.next;
162				op->common.next = NULL;
163
164#ifdef ACPI_DISASSEMBLER
165				if (walk_state->method_node !=
166				    acpi_gbl_root_node) {
167
168					/* More verbose if not module-level code */
169
170					acpi_os_printf("Failed at ");
171					acpi_dm_disassemble(next_walk_state, op,
172							    ACPI_UINT32_MAX);
173				}
174#endif
175				op->common.next = next;
176			}
177		} else {
178			/*
179			 * This method has called another method
180			 * NOTE: the method call parse subtree is already deleted at
181			 * this point, so we cannot disassemble the method invocation.
182			 */
183			ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH,
184					      "Call to method "));
185			acpi_ds_print_node_pathname(previous_method, NULL);
186		}
187
188		previous_method = next_walk_state->method_node;
189		next_walk_state = next_walk_state->next;
190		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n"));
191	}
192
193	return_VOID;
194}
195
196#else
197void
198acpi_ds_dump_method_stack(acpi_status status,
199			  struct acpi_walk_state *walk_state,
200			  union acpi_parse_object *op)
201{
202	return;
203}
204
205#endif
206