1 /******************************************************************************
2 *
3 * Module Name: aeexception - Exception and signal handlers
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "aecommon.h"
45
46 #define _COMPONENT ACPI_TOOLS
47 ACPI_MODULE_NAME ("aeexception")
48
49
50 /* Local prototypes */
51
52 static void
53 AeDisplayMethodCallStack (
54 void);
55
56
57 UINT32 SigintCount = 0;
58 #define ACPI_MAX_CONTROL_C 5
59
60
61 /******************************************************************************
62 *
63 * FUNCTION: AeExceptionHandler
64 *
65 * PARAMETERS: Standard exception handler parameters
66 *
67 * RETURN: Status
68 *
69 * DESCRIPTION: System exception handler for AcpiExec utility. Called from
70 * the core ACPICA code after any exception during method
71 * execution.
72 *
73 *****************************************************************************/
74
75 ACPI_STATUS
AeExceptionHandler(ACPI_STATUS AmlStatus,ACPI_NAME Name,UINT16 Opcode,UINT32 AmlOffset,void * Context)76 AeExceptionHandler (
77 ACPI_STATUS AmlStatus,
78 ACPI_NAME Name,
79 UINT16 Opcode,
80 UINT32 AmlOffset,
81 void *Context)
82 {
83 ACPI_STATUS NewAmlStatus = AmlStatus;
84 ACPI_STATUS Status;
85 ACPI_BUFFER ReturnObj;
86 ACPI_OBJECT_LIST ArgList;
87 ACPI_OBJECT Arg[3];
88 const char *Exception;
89 ACPI_HANDLE ErrHandle;
90
91
92 Exception = AcpiFormatException (AmlStatus);
93
94 if (AcpiGbl_VerboseHandlers)
95 {
96 AcpiOsPrintf (AE_PREFIX
97 "Exception %s during execution\n", Exception);
98
99 if (Name)
100 {
101 if (ACPI_COMPARE_NAMESEG (&Name, ACPI_ROOT_PATHNAME))
102 {
103 AcpiOsPrintf (AE_PREFIX
104 "Evaluating executable code at [%s]\n", ACPI_NAMESPACE_ROOT);
105 }
106 else
107 {
108 AcpiOsPrintf (AE_PREFIX
109 "Evaluating Method or Node: [%4.4s]\n", (char *) &Name);
110 }
111 }
112
113 /* Be terse about loop timeouts */
114
115 if ((AmlStatus == AE_AML_LOOP_TIMEOUT) && AcpiGbl_AbortLoopOnTimeout)
116 {
117 AcpiOsPrintf (AE_PREFIX "Aborting loop after timeout\n");
118 return (AE_OK);
119 }
120
121 AcpiOsPrintf ("\n" AE_PREFIX
122 "AML Opcode [%s], Method Offset ~%5.5X\n",
123 AcpiPsGetOpcodeName (Opcode), AmlOffset);
124 }
125
126 /* Invoke the _ERR method if present */
127
128 Status = AcpiGetHandle (NULL, "\\_ERR", &ErrHandle);
129 if (ACPI_FAILURE (Status))
130 {
131 goto Cleanup;
132 }
133
134 /* Setup parameter object */
135
136 ArgList.Count = 3;
137 ArgList.Pointer = Arg;
138
139 Arg[0].Type = ACPI_TYPE_INTEGER;
140 Arg[0].Integer.Value = AmlStatus;
141
142 Arg[1].Type = ACPI_TYPE_STRING;
143 Arg[1].String.Pointer = ACPI_CAST_PTR (char, Exception);
144 Arg[1].String.Length = strlen (Exception);
145
146 Arg[2].Type = ACPI_TYPE_INTEGER;
147 Arg[2].Integer.Value = AcpiOsGetThreadId();
148
149 /* Setup return buffer */
150
151 ReturnObj.Pointer = NULL;
152 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
153
154 Status = AcpiEvaluateObject (ErrHandle, NULL, &ArgList, &ReturnObj);
155 if (ACPI_SUCCESS (Status))
156 {
157 if (ReturnObj.Pointer)
158 {
159 /* Override original status */
160
161 NewAmlStatus = (ACPI_STATUS)
162 ((ACPI_OBJECT *) ReturnObj.Pointer)->Integer.Value;
163
164 /* Free a buffer created via ACPI_ALLOCATE_BUFFER */
165
166 AcpiOsFree (ReturnObj.Pointer);
167 }
168 }
169 else if (Status != AE_NOT_FOUND)
170 {
171 AcpiOsPrintf (AE_PREFIX
172 "Could not execute _ERR method, %s\n",
173 AcpiFormatException (Status));
174 }
175
176 Cleanup:
177
178 if (AcpiGbl_IgnoreErrors)
179 {
180 /* Global option to ignore all method errors, just return OK */
181
182 NewAmlStatus = AE_OK;
183 }
184 if (NewAmlStatus != AmlStatus)
185 {
186 /* Request to override actual status with a different status */
187
188 AcpiOsPrintf (AE_PREFIX
189 "Exception override, new status %s\n\n",
190 AcpiFormatException (NewAmlStatus));
191 }
192
193 return (NewAmlStatus);
194 }
195
196
197 /******************************************************************************
198 *
199 * FUNCTION: AeSignalHandler
200 *
201 * PARAMETERS: Sig
202 *
203 * RETURN: none
204 *
205 * DESCRIPTION: Master signal handler. Currently handles SIGINT (ctrl-c),
206 * and SIGSEGV (Segment violation).
207 *
208 *****************************************************************************/
209
210 void ACPI_SYSTEM_XFACE
AeSignalHandler(int Sig)211 AeSignalHandler (
212 int Sig)
213 {
214
215 fflush(stdout);
216 AcpiOsPrintf ("\n" AE_PREFIX);
217
218 switch (Sig)
219 {
220 case SIGINT:
221 signal(Sig, SIG_IGN);
222 AcpiOsPrintf ("<Control-C>\n");
223
224 /* Force exit on multiple control-c */
225
226 SigintCount++;
227 if (SigintCount >= ACPI_MAX_CONTROL_C)
228 {
229 _exit (0);
230 }
231
232 /* Abort the application if there are no methods executing */
233
234 if (!AcpiGbl_MethodExecuting)
235 {
236 break;
237 }
238
239 /*
240 * Abort the method(s). This will also dump the method call
241 * stack so there is no need to do it here. The application
242 * will then drop back into the debugger interface.
243 */
244 AcpiGbl_AbortMethod = TRUE;
245 AcpiOsPrintf (AE_PREFIX "Control Method Call Stack:\n");
246 signal (SIGINT, AeSignalHandler);
247 return;
248
249 case SIGSEGV:
250 AcpiOsPrintf ("Segmentation Fault\n");
251 AeDisplayMethodCallStack ();
252 break;
253
254 default:
255 AcpiOsPrintf ("Unknown Signal, %X\n", Sig);
256 break;
257 }
258
259 /* Terminate application -- cleanup then exit */
260
261 AcpiOsPrintf (AE_PREFIX "Terminating\n");
262 (void) AcpiOsTerminate ();
263 _exit (0);
264 }
265
266
267 /******************************************************************************
268 *
269 * FUNCTION: AeDisplayMethodCallStack
270 *
271 * PARAMETERS: None
272 *
273 * RETURN: None
274 *
275 * DESCRIPTION: Display current method call stack, if possible.
276 *
277 * NOTE: Currently only called from a SIGSEGV, so AcpiExec is about
278 * to terminate.
279 *
280 *****************************************************************************/
281
282 static void
AeDisplayMethodCallStack(void)283 AeDisplayMethodCallStack (
284 void)
285 {
286 ACPI_WALK_STATE *WalkState;
287 ACPI_THREAD_STATE *ThreadList = AcpiGbl_CurrentWalkList;
288 char *FullPathname = NULL;
289
290
291 if (!AcpiGbl_MethodExecuting)
292 {
293 AcpiOsPrintf (AE_PREFIX "No method is executing\n");
294 return;
295 }
296
297 /*
298 * Try to find the currently executing control method(s)
299 *
300 * Note: The following code may fault if the data structures are
301 * in an indeterminate state when the interrupt occurs. However,
302 * in practice, this works quite well and can provide very
303 * valuable information.
304 *
305 * 1) Walk the global thread list
306 */
307 while (ThreadList &&
308 (ThreadList->DescriptorType == ACPI_DESC_TYPE_STATE_THREAD))
309 {
310 /* 2) Walk the walk state list for this thread */
311
312 WalkState = ThreadList->WalkStateList;
313 while (WalkState &&
314 (WalkState->DescriptorType == ACPI_DESC_TYPE_WALK))
315 {
316 /* An executing control method */
317
318 if (WalkState->MethodNode)
319 {
320 FullPathname = AcpiNsGetExternalPathname (
321 WalkState->MethodNode);
322
323 AcpiOsPrintf (AE_PREFIX
324 "Executing Method: %s\n", FullPathname);
325 }
326
327 /* Execution of a deferred opcode/node */
328
329 if (WalkState->DeferredNode)
330 {
331 FullPathname = AcpiNsGetExternalPathname (
332 WalkState->DeferredNode);
333
334 AcpiOsPrintf (AE_PREFIX
335 "Evaluating deferred node: %s\n", FullPathname);
336 }
337
338 /* Get the currently executing AML opcode */
339
340 if ((WalkState->Opcode != AML_INT_METHODCALL_OP) &&
341 FullPathname)
342 {
343 AcpiOsPrintf (AE_PREFIX
344 "Current AML Opcode in %s: [%s]-0x%4.4X at %p\n",
345 FullPathname, AcpiPsGetOpcodeName (WalkState->Opcode),
346 WalkState->Opcode, WalkState->Aml);
347 }
348
349 if (FullPathname)
350 {
351 ACPI_FREE (FullPathname);
352 FullPathname = NULL;
353 }
354
355 WalkState = WalkState->Next;
356 }
357
358 ThreadList = ThreadList->Next;
359 }
360 }
361