xref: /linux/drivers/acpi/acpica/dsdebug.c (revision 4f77c3462308c62ffe7129cc18b9ac937f44b5a5)
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
20 ACPI_MODULE_NAME("dsdebug")
21 
22 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
23 /* Local prototypes */
24 static void
25 acpi_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 
40 static void
41 acpi_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 
88 void
89 acpi_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
197 void
198 acpi_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