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
52static void
53AeDisplayMethodCallStack (
54    void);
55
56
57UINT32                      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
75ACPI_STATUS
76AeExceptionHandler (
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
176Cleanup:
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
210void ACPI_SYSTEM_XFACE
211AeSignalHandler (
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
282static void
283AeDisplayMethodCallStack (
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