| /****************************************************************************** |
| * |
| * Module Name: aeexception - Exception and signal handlers |
| * |
| *****************************************************************************/ |
| |
| /* |
| * Copyright (C) 2000 - 2022, Intel Corp. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions, and the following disclaimer, |
| * without modification. |
| * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
| * substantially similar to the "NO WARRANTY" disclaimer below |
| * ("Disclaimer") and any redistribution must be conditioned upon |
| * including a substantially similar Disclaimer requirement for further |
| * binary redistribution. |
| * 3. Neither the names of the above-listed copyright holders nor the names |
| * of any contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * Alternatively, this software may be distributed under the terms of the |
| * GNU General Public License ("GPL") version 2 as published by the Free |
| * Software Foundation. |
| * |
| * NO WARRANTY |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGES. |
| */ |
| |
| #include "aecommon.h" |
| |
| #define _COMPONENT ACPI_TOOLS |
| ACPI_MODULE_NAME ("aeexception") |
| |
| |
| /* Local prototypes */ |
| |
| static void |
| AeDisplayMethodCallStack ( |
| void); |
| |
| |
| UINT32 SigintCount = 0; |
| #define ACPI_MAX_CONTROL_C 5 |
| |
| |
| /****************************************************************************** |
| * |
| * FUNCTION: AeExceptionHandler |
| * |
| * PARAMETERS: Standard exception handler parameters |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: System exception handler for AcpiExec utility. Called from |
| * the core ACPICA code after any exception during method |
| * execution. |
| * |
| *****************************************************************************/ |
| |
| ACPI_STATUS |
| AeExceptionHandler ( |
| ACPI_STATUS AmlStatus, |
| ACPI_NAME Name, |
| UINT16 Opcode, |
| UINT32 AmlOffset, |
| void *Context) |
| { |
| ACPI_STATUS NewAmlStatus = AmlStatus; |
| ACPI_STATUS Status; |
| ACPI_BUFFER ReturnObj; |
| ACPI_OBJECT_LIST ArgList; |
| ACPI_OBJECT Arg[3]; |
| const char *Exception; |
| ACPI_HANDLE ErrHandle; |
| |
| |
| Exception = AcpiFormatException (AmlStatus); |
| |
| if (AcpiGbl_VerboseHandlers) |
| { |
| AcpiOsPrintf (AE_PREFIX |
| "Exception %s during execution\n", Exception); |
| |
| if (Name) |
| { |
| if (ACPI_COMPARE_NAMESEG (&Name, ACPI_ROOT_PATHNAME)) |
| { |
| AcpiOsPrintf (AE_PREFIX |
| "Evaluating executable code at [%s]\n", ACPI_NAMESPACE_ROOT); |
| } |
| else |
| { |
| AcpiOsPrintf (AE_PREFIX |
| "Evaluating Method or Node: [%4.4s]\n", (char *) &Name); |
| } |
| } |
| |
| /* Be terse about loop timeouts */ |
| |
| if ((AmlStatus == AE_AML_LOOP_TIMEOUT) && AcpiGbl_AbortLoopOnTimeout) |
| { |
| AcpiOsPrintf (AE_PREFIX "Aborting loop after timeout\n"); |
| return (AE_OK); |
| } |
| |
| AcpiOsPrintf ("\n" AE_PREFIX |
| "AML Opcode [%s], Method Offset ~%5.5X\n", |
| AcpiPsGetOpcodeName (Opcode), AmlOffset); |
| } |
| |
| /* Invoke the _ERR method if present */ |
| |
| Status = AcpiGetHandle (NULL, "\\_ERR", &ErrHandle); |
| if (ACPI_FAILURE (Status)) |
| { |
| goto Cleanup; |
| } |
| |
| /* Setup parameter object */ |
| |
| ArgList.Count = 3; |
| ArgList.Pointer = Arg; |
| |
| Arg[0].Type = ACPI_TYPE_INTEGER; |
| Arg[0].Integer.Value = AmlStatus; |
| |
| Arg[1].Type = ACPI_TYPE_STRING; |
| Arg[1].String.Pointer = ACPI_CAST_PTR (char, Exception); |
| Arg[1].String.Length = strlen (Exception); |
| |
| Arg[2].Type = ACPI_TYPE_INTEGER; |
| Arg[2].Integer.Value = AcpiOsGetThreadId(); |
| |
| /* Setup return buffer */ |
| |
| ReturnObj.Pointer = NULL; |
| ReturnObj.Length = ACPI_ALLOCATE_BUFFER; |
| |
| Status = AcpiEvaluateObject (ErrHandle, NULL, &ArgList, &ReturnObj); |
| if (ACPI_SUCCESS (Status)) |
| { |
| if (ReturnObj.Pointer) |
| { |
| /* Override original status */ |
| |
| NewAmlStatus = (ACPI_STATUS) |
| ((ACPI_OBJECT *) ReturnObj.Pointer)->Integer.Value; |
| |
| /* Free a buffer created via ACPI_ALLOCATE_BUFFER */ |
| |
| AcpiOsFree (ReturnObj.Pointer); |
| } |
| } |
| else if (Status != AE_NOT_FOUND) |
| { |
| AcpiOsPrintf (AE_PREFIX |
| "Could not execute _ERR method, %s\n", |
| AcpiFormatException (Status)); |
| } |
| |
| Cleanup: |
| |
| if (AcpiGbl_IgnoreErrors) |
| { |
| /* Global option to ignore all method errors, just return OK */ |
| |
| NewAmlStatus = AE_OK; |
| } |
| if (NewAmlStatus != AmlStatus) |
| { |
| /* Request to override actual status with a different status */ |
| |
| AcpiOsPrintf (AE_PREFIX |
| "Exception override, new status %s\n\n", |
| AcpiFormatException (NewAmlStatus)); |
| } |
| |
| return (NewAmlStatus); |
| } |
| |
| |
| /****************************************************************************** |
| * |
| * FUNCTION: AeSignalHandler |
| * |
| * PARAMETERS: Sig |
| * |
| * RETURN: none |
| * |
| * DESCRIPTION: Master signal handler. Currently handles SIGINT (ctrl-c), |
| * and SIGSEGV (Segment violation). |
| * |
| *****************************************************************************/ |
| |
| void ACPI_SYSTEM_XFACE |
| AeSignalHandler ( |
| int Sig) |
| { |
| |
| fflush(stdout); |
| AcpiOsPrintf ("\n" AE_PREFIX); |
| |
| switch (Sig) |
| { |
| case SIGINT: |
| signal(Sig, SIG_IGN); |
| AcpiOsPrintf ("<Control-C>\n"); |
| |
| /* Force exit on multiple control-c */ |
| |
| SigintCount++; |
| if (SigintCount >= ACPI_MAX_CONTROL_C) |
| { |
| _exit (0); |
| } |
| |
| /* Abort the application if there are no methods executing */ |
| |
| if (!AcpiGbl_MethodExecuting) |
| { |
| break; |
| } |
| |
| /* |
| * Abort the method(s). This will also dump the method call |
| * stack so there is no need to do it here. The application |
| * will then drop back into the debugger interface. |
| */ |
| AcpiGbl_AbortMethod = TRUE; |
| AcpiOsPrintf (AE_PREFIX "Control Method Call Stack:\n"); |
| signal (SIGINT, AeSignalHandler); |
| return; |
| |
| case SIGSEGV: |
| AcpiOsPrintf ("Segmentation Fault\n"); |
| AeDisplayMethodCallStack (); |
| break; |
| |
| default: |
| AcpiOsPrintf ("Unknown Signal, %X\n", Sig); |
| break; |
| } |
| |
| /* Terminate application -- cleanup then exit */ |
| |
| AcpiOsPrintf (AE_PREFIX "Terminating\n"); |
| (void) AcpiOsTerminate (); |
| _exit (0); |
| } |
| |
| |
| /****************************************************************************** |
| * |
| * FUNCTION: AeDisplayMethodCallStack |
| * |
| * PARAMETERS: None |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Display current method call stack, if possible. |
| * |
| * NOTE: Currently only called from a SIGSEGV, so AcpiExec is about |
| * to terminate. |
| * |
| *****************************************************************************/ |
| |
| static void |
| AeDisplayMethodCallStack ( |
| void) |
| { |
| ACPI_WALK_STATE *WalkState; |
| ACPI_THREAD_STATE *ThreadList = AcpiGbl_CurrentWalkList; |
| char *FullPathname = NULL; |
| |
| |
| if (!AcpiGbl_MethodExecuting) |
| { |
| AcpiOsPrintf (AE_PREFIX "No method is executing\n"); |
| return; |
| } |
| |
| /* |
| * Try to find the currently executing control method(s) |
| * |
| * Note: The following code may fault if the data structures are |
| * in an indeterminate state when the interrupt occurs. However, |
| * in practice, this works quite well and can provide very |
| * valuable information. |
| * |
| * 1) Walk the global thread list |
| */ |
| while (ThreadList && |
| (ThreadList->DescriptorType == ACPI_DESC_TYPE_STATE_THREAD)) |
| { |
| /* 2) Walk the walk state list for this thread */ |
| |
| WalkState = ThreadList->WalkStateList; |
| while (WalkState && |
| (WalkState->DescriptorType == ACPI_DESC_TYPE_WALK)) |
| { |
| /* An executing control method */ |
| |
| if (WalkState->MethodNode) |
| { |
| FullPathname = AcpiNsGetExternalPathname ( |
| WalkState->MethodNode); |
| |
| AcpiOsPrintf (AE_PREFIX |
| "Executing Method: %s\n", FullPathname); |
| } |
| |
| /* Execution of a deferred opcode/node */ |
| |
| if (WalkState->DeferredNode) |
| { |
| FullPathname = AcpiNsGetExternalPathname ( |
| WalkState->DeferredNode); |
| |
| AcpiOsPrintf (AE_PREFIX |
| "Evaluating deferred node: %s\n", FullPathname); |
| } |
| |
| /* Get the currently executing AML opcode */ |
| |
| if ((WalkState->Opcode != AML_INT_METHODCALL_OP) && |
| FullPathname) |
| { |
| AcpiOsPrintf (AE_PREFIX |
| "Current AML Opcode in %s: [%s]-0x%4.4X at %p\n", |
| FullPathname, AcpiPsGetOpcodeName (WalkState->Opcode), |
| WalkState->Opcode, WalkState->Aml); |
| } |
| |
| if (FullPathname) |
| { |
| ACPI_FREE (FullPathname); |
| FullPathname = NULL; |
| } |
| |
| WalkState = WalkState->Next; |
| } |
| |
| ThreadList = ThreadList->Next; |
| } |
| } |