Home | History | Annotate | Line # | Download | only in debugger
dbxface.c revision 1.1.1.16
      1 /*******************************************************************************
      2  *
      3  * Module Name: dbxface - AML Debugger external interfaces
      4  *
      5  ******************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2020, 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 MERCHANTIBILITY 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 "acpi.h"
     45 #include "accommon.h"
     46 #include "amlcode.h"
     47 #include "acdebug.h"
     48 #include "acinterp.h"
     49 #include "acparser.h"
     50 
     51 
     52 #define _COMPONENT          ACPI_CA_DEBUGGER
     53         ACPI_MODULE_NAME    ("dbxface")
     54 
     55 
     56 /* Local prototypes */
     57 
     58 static ACPI_STATUS
     59 AcpiDbStartCommand (
     60     ACPI_WALK_STATE         *WalkState,
     61     ACPI_PARSE_OBJECT       *Op);
     62 
     63 #ifdef ACPI_OBSOLETE_FUNCTIONS
     64 void
     65 AcpiDbMethodEnd (
     66     ACPI_WALK_STATE         *WalkState);
     67 #endif
     68 
     69 #ifdef ACPI_DISASSEMBLER
     70 static ACPI_PARSE_OBJECT *
     71 AcpiDbGetDisplayOp (
     72     ACPI_WALK_STATE         *WalkState,
     73     ACPI_PARSE_OBJECT       *Op);
     74 #endif
     75 
     76 /*******************************************************************************
     77  *
     78  * FUNCTION:    AcpiDbStartCommand
     79  *
     80  * PARAMETERS:  WalkState       - Current walk
     81  *              Op              - Current executing Op, from AML interpreter
     82  *
     83  * RETURN:      Status
     84  *
     85  * DESCRIPTION: Enter debugger command loop
     86  *
     87  ******************************************************************************/
     88 
     89 static ACPI_STATUS
     90 AcpiDbStartCommand (
     91     ACPI_WALK_STATE         *WalkState,
     92     ACPI_PARSE_OBJECT       *Op)
     93 {
     94     ACPI_STATUS             Status;
     95 
     96 
     97     /* TBD: [Investigate] are there namespace locking issues here? */
     98 
     99     /* AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); */
    100 
    101     /* Go into the command loop and await next user command */
    102 
    103 
    104     AcpiGbl_MethodExecuting = TRUE;
    105     Status = AE_CTRL_TRUE;
    106 
    107     while (Status == AE_CTRL_TRUE)
    108     {
    109         /* Notify the completion of the command */
    110 
    111         Status = AcpiOsNotifyCommandComplete ();
    112         if (ACPI_FAILURE (Status))
    113         {
    114             goto ErrorExit;
    115         }
    116 
    117         /* Wait the readiness of the command */
    118 
    119         Status = AcpiOsWaitCommandReady ();
    120         if (ACPI_FAILURE (Status))
    121         {
    122             goto ErrorExit;
    123         }
    124 
    125         Status = AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, WalkState, Op);
    126     }
    127 
    128     /* AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); */
    129 
    130 ErrorExit:
    131     if (ACPI_FAILURE (Status) && Status != AE_CTRL_TERMINATE)
    132     {
    133         ACPI_EXCEPTION ((AE_INFO, Status,
    134             "While parsing/handling command line"));
    135     }
    136     return (Status);
    137 }
    138 
    139 
    140 /*******************************************************************************
    141  *
    142  * FUNCTION:    AcpiDbSignalBreakPoint
    143  *
    144  * PARAMETERS:  WalkState       - Current walk
    145  *
    146  * RETURN:      Status
    147  *
    148  * DESCRIPTION: Called for AML_BREAKPOINT_OP
    149  *
    150  ******************************************************************************/
    151 
    152 void
    153 AcpiDbSignalBreakPoint (
    154     ACPI_WALK_STATE         *WalkState)
    155 {
    156 
    157 #ifndef ACPI_APPLICATION
    158     if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ())
    159     {
    160         return;
    161     }
    162 #endif
    163 
    164     /*
    165      * Set the single-step flag. This will cause the debugger (if present)
    166      * to break to the console within the AML debugger at the start of the
    167      * next AML instruction.
    168      */
    169     AcpiGbl_CmSingleStep = TRUE;
    170     AcpiOsPrintf ("**break** Executed AML BreakPoint opcode\n");
    171 }
    172 
    173 
    174 #ifdef ACPI_DISASSEMBLER
    175 /*******************************************************************************
    176  *
    177  * FUNCTION:    AcpiDbGetDisplayOp
    178  *
    179  * PARAMETERS:  WalkState       - Current walk
    180  *              Op              - Current executing op (from aml interpreter)
    181  *
    182  * RETURN:      Opcode to display
    183  *
    184  * DESCRIPTION: Find the opcode to display during single stepping
    185  *
    186  ******************************************************************************/
    187 
    188 static ACPI_PARSE_OBJECT *
    189 AcpiDbGetDisplayOp (
    190     ACPI_WALK_STATE         *WalkState,
    191     ACPI_PARSE_OBJECT       *Op)
    192 {
    193     ACPI_PARSE_OBJECT       *DisplayOp;
    194     ACPI_PARSE_OBJECT       *ParentOp;
    195 
    196     DisplayOp = Op;
    197     ParentOp = Op->Common.Parent;
    198     if (ParentOp)
    199     {
    200         if ((WalkState->ControlState) &&
    201             (WalkState->ControlState->Common.State ==
    202                 ACPI_CONTROL_PREDICATE_EXECUTING))
    203         {
    204             /*
    205              * We are executing the predicate of an IF or WHILE statement
    206              * Search upwards for the containing IF or WHILE so that the
    207              * entire predicate can be displayed.
    208              */
    209             while (ParentOp)
    210             {
    211                 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) ||
    212                     (ParentOp->Common.AmlOpcode == AML_WHILE_OP))
    213                 {
    214                     DisplayOp = ParentOp;
    215                     break;
    216                 }
    217                 ParentOp = ParentOp->Common.Parent;
    218             }
    219         }
    220         else
    221         {
    222             while (ParentOp)
    223             {
    224                 if ((ParentOp->Common.AmlOpcode == AML_IF_OP)     ||
    225                     (ParentOp->Common.AmlOpcode == AML_ELSE_OP)   ||
    226                     (ParentOp->Common.AmlOpcode == AML_SCOPE_OP)  ||
    227                     (ParentOp->Common.AmlOpcode == AML_METHOD_OP) ||
    228                     (ParentOp->Common.AmlOpcode == AML_WHILE_OP))
    229                 {
    230                     break;
    231                 }
    232                 DisplayOp = ParentOp;
    233                 ParentOp = ParentOp->Common.Parent;
    234             }
    235         }
    236     }
    237     return DisplayOp;
    238 }
    239 #endif
    240 
    241 
    242 /*******************************************************************************
    243  *
    244  * FUNCTION:    AcpiDbSingleStep
    245  *
    246  * PARAMETERS:  WalkState       - Current walk
    247  *              Op              - Current executing op (from aml interpreter)
    248  *              OpcodeClass     - Class of the current AML Opcode
    249  *
    250  * RETURN:      Status
    251  *
    252  * DESCRIPTION: Called just before execution of an AML opcode.
    253  *
    254  ******************************************************************************/
    255 
    256 ACPI_STATUS
    257 AcpiDbSingleStep (
    258     ACPI_WALK_STATE         *WalkState,
    259     ACPI_PARSE_OBJECT       *Op,
    260     UINT32                  OpcodeClass)
    261 {
    262     ACPI_PARSE_OBJECT       *Next;
    263     ACPI_STATUS             Status = AE_OK;
    264     UINT32                  OriginalDebugLevel;
    265     UINT32                  AmlOffset;
    266 
    267 
    268     ACPI_FUNCTION_ENTRY ();
    269 
    270 
    271 #ifndef ACPI_APPLICATION
    272     if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ())
    273     {
    274         return (AE_OK);
    275     }
    276 #endif
    277 
    278     /* Check the abort flag */
    279 
    280     if (AcpiGbl_AbortMethod)
    281     {
    282         AcpiGbl_AbortMethod = FALSE;
    283         return (AE_ABORT_METHOD);
    284     }
    285 
    286     AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
    287         WalkState->ParserState.AmlStart);
    288 
    289     /* Check for single-step breakpoint */
    290 
    291     if (WalkState->MethodBreakpoint &&
    292        (WalkState->MethodBreakpoint <= AmlOffset))
    293     {
    294         /* Check if the breakpoint has been reached or passed */
    295         /* Hit the breakpoint, resume single step, reset breakpoint */
    296 
    297         AcpiOsPrintf ("***Break*** at AML offset %X\n", AmlOffset);
    298         AcpiGbl_CmSingleStep = TRUE;
    299         AcpiGbl_StepToNextCall = FALSE;
    300         WalkState->MethodBreakpoint = 0;
    301     }
    302 
    303     /* Check for user breakpoint (Must be on exact Aml offset) */
    304 
    305     else if (WalkState->UserBreakpoint &&
    306             (WalkState->UserBreakpoint == AmlOffset))
    307     {
    308         AcpiOsPrintf ("***UserBreakpoint*** at AML offset %X\n",
    309             AmlOffset);
    310         AcpiGbl_CmSingleStep = TRUE;
    311         AcpiGbl_StepToNextCall = FALSE;
    312         WalkState->MethodBreakpoint = 0;
    313     }
    314 
    315     /*
    316      * Check if this is an opcode that we are interested in --
    317      * namely, opcodes that have arguments
    318      */
    319     if (Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP)
    320     {
    321         return (AE_OK);
    322     }
    323 
    324     switch (OpcodeClass)
    325     {
    326     case AML_CLASS_UNKNOWN:
    327     case AML_CLASS_ARGUMENT:    /* constants, literals, etc. do nothing */
    328 
    329         return (AE_OK);
    330 
    331     default:
    332 
    333         /* All other opcodes -- continue */
    334         break;
    335     }
    336 
    337     /*
    338      * Under certain debug conditions, display this opcode and its operands
    339      */
    340     if ((AcpiGbl_DbOutputToFile)            ||
    341         (AcpiGbl_CmSingleStep)              ||
    342         (AcpiDbgLevel & ACPI_LV_PARSE))
    343     {
    344         if ((AcpiGbl_DbOutputToFile)        ||
    345             (AcpiDbgLevel & ACPI_LV_PARSE))
    346         {
    347             AcpiOsPrintf ("\nAML Debug: Next AML Opcode to execute:\n");
    348         }
    349 
    350         /*
    351          * Display this op (and only this op - zero out the NEXT field
    352          * temporarily, and disable parser trace output for the duration of
    353          * the display because we don't want the extraneous debug output)
    354          */
    355         OriginalDebugLevel = AcpiDbgLevel;
    356         AcpiDbgLevel &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
    357         Next = Op->Common.Next;
    358         Op->Common.Next = NULL;
    359 
    360         /* Now we can disassemble and display it */
    361 
    362 #ifdef ACPI_DISASSEMBLER
    363         AcpiDmDisassemble (WalkState, AcpiDbGetDisplayOp (WalkState, Op),
    364             ACPI_UINT32_MAX);
    365 #else
    366         /*
    367          * The AML Disassembler is not configured - at least we can
    368          * display the opcode value and name
    369          */
    370         AcpiOsPrintf ("AML Opcode: %4.4X  %s\n", Op->Common.AmlOpcode,
    371             AcpiPsGetOpcodeName (Op->Common.AmlOpcode));
    372 #endif
    373 
    374         if ((Op->Common.AmlOpcode == AML_IF_OP) ||
    375             (Op->Common.AmlOpcode == AML_WHILE_OP))
    376         {
    377             if (WalkState->ControlState->Common.Value)
    378             {
    379                 AcpiOsPrintf ("Predicate = [True], IF block was executed\n");
    380             }
    381             else
    382             {
    383                 AcpiOsPrintf ("Predicate = [False], Skipping IF block\n");
    384             }
    385         }
    386         else if (Op->Common.AmlOpcode == AML_ELSE_OP)
    387         {
    388             AcpiOsPrintf ("Predicate = [False], ELSE block was executed\n");
    389         }
    390 
    391         /* Restore everything */
    392 
    393         Op->Common.Next = Next;
    394         AcpiOsPrintf ("\n");
    395         if ((AcpiGbl_DbOutputToFile)        ||
    396             (AcpiDbgLevel & ACPI_LV_PARSE))
    397         {
    398             AcpiOsPrintf ("\n");
    399         }
    400         AcpiDbgLevel = OriginalDebugLevel;
    401     }
    402 
    403     /* If we are not single stepping, just continue executing the method */
    404 
    405     if (!AcpiGbl_CmSingleStep)
    406     {
    407         return (AE_OK);
    408     }
    409 
    410     /*
    411      * If we are executing a step-to-call command,
    412      * Check if this is a method call.
    413      */
    414     if (AcpiGbl_StepToNextCall)
    415     {
    416         if (Op->Common.AmlOpcode != AML_INT_METHODCALL_OP)
    417         {
    418             /* Not a method call, just keep executing */
    419 
    420             return (AE_OK);
    421         }
    422 
    423         /* Found a method call, stop executing */
    424 
    425         AcpiGbl_StepToNextCall = FALSE;
    426     }
    427 
    428     /*
    429      * If the next opcode is a method call, we will "step over" it
    430      * by default.
    431      */
    432     if (Op->Common.AmlOpcode == AML_INT_METHODCALL_OP)
    433     {
    434         /* Force no more single stepping while executing called method */
    435 
    436         AcpiGbl_CmSingleStep = FALSE;
    437 
    438         /*
    439          * Set the breakpoint on/before the call, it will stop execution
    440          * as soon as we return
    441          */
    442         WalkState->MethodBreakpoint = 1;  /* Must be non-zero! */
    443     }
    444 
    445 
    446     AcpiExExitInterpreter ();
    447     Status = AcpiDbStartCommand (WalkState, Op);
    448     AcpiExEnterInterpreter ();
    449 
    450     /* User commands complete, continue execution of the interrupted method */
    451 
    452     return (Status);
    453 }
    454 
    455 
    456 /*******************************************************************************
    457  *
    458  * FUNCTION:    AcpiInitializeDebugger
    459  *
    460  * PARAMETERS:  None
    461  *
    462  * RETURN:      Status
    463  *
    464  * DESCRIPTION: Init and start debugger
    465  *
    466  ******************************************************************************/
    467 
    468 ACPI_STATUS
    469 AcpiInitializeDebugger (
    470     void)
    471 {
    472     ACPI_STATUS             Status;
    473 
    474 
    475     ACPI_FUNCTION_TRACE (AcpiInitializeDebugger);
    476 
    477 
    478     /* Init globals */
    479 
    480     AcpiGbl_DbBuffer            = NULL;
    481     AcpiGbl_DbFilename          = NULL;
    482     AcpiGbl_DbOutputToFile      = FALSE;
    483 
    484     AcpiGbl_DbDebugLevel        = ACPI_LV_VERBOSITY2;
    485     AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
    486     AcpiGbl_DbOutputFlags       = ACPI_DB_CONSOLE_OUTPUT;
    487 
    488     AcpiGbl_DbOpt_NoIniMethods  = FALSE;
    489     AcpiGbl_DbOpt_NoRegionSupport = FALSE;
    490 
    491     AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE);
    492     if (!AcpiGbl_DbBuffer)
    493     {
    494         return_ACPI_STATUS (AE_NO_MEMORY);
    495     }
    496     memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE);
    497 
    498     /* Initial scope is the root */
    499 
    500     AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX;
    501     AcpiGbl_DbScopeBuf [1] =  0;
    502     AcpiGbl_DbScopeNode = AcpiGbl_RootNode;
    503 
    504     /* Initialize user commands loop */
    505 
    506     AcpiGbl_DbTerminateLoop = FALSE;
    507 
    508     /*
    509      * If configured for multi-thread support, the debug executor runs in
    510      * a separate thread so that the front end can be in another address
    511      * space, environment, or even another machine.
    512      */
    513     if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED)
    514     {
    515         /* These were created with one unit, grab it */
    516 
    517         Status = AcpiOsInitializeDebugger ();
    518         if (ACPI_FAILURE (Status))
    519         {
    520             AcpiOsPrintf ("Could not get debugger mutex\n");
    521             return_ACPI_STATUS (Status);
    522         }
    523 
    524         /* Create the debug execution thread to execute commands */
    525 
    526         AcpiGbl_DbThreadsTerminated = FALSE;
    527         Status = AcpiOsExecute (OSL_DEBUGGER_MAIN_THREAD,
    528             AcpiDbExecuteThread, NULL);
    529         if (ACPI_FAILURE (Status))
    530         {
    531             ACPI_EXCEPTION ((AE_INFO, Status,
    532                 "Could not start debugger thread"));
    533             AcpiGbl_DbThreadsTerminated = TRUE;
    534             return_ACPI_STATUS (Status);
    535         }
    536     }
    537     else
    538     {
    539         AcpiGbl_DbThreadId = AcpiOsGetThreadId ();
    540     }
    541 
    542     return_ACPI_STATUS (AE_OK);
    543 }
    544 
    545 ACPI_EXPORT_SYMBOL (AcpiInitializeDebugger)
    546 
    547 
    548 /*******************************************************************************
    549  *
    550  * FUNCTION:    AcpiTerminateDebugger
    551  *
    552  * PARAMETERS:  None
    553  *
    554  * RETURN:      None
    555  *
    556  * DESCRIPTION: Stop debugger
    557  *
    558  ******************************************************************************/
    559 
    560 void
    561 AcpiTerminateDebugger (
    562     void)
    563 {
    564 
    565     /* Terminate the AML Debugger */
    566 
    567     AcpiGbl_DbTerminateLoop = TRUE;
    568 
    569     if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED)
    570     {
    571         /* Wait the AML Debugger threads */
    572 
    573         while (!AcpiGbl_DbThreadsTerminated)
    574         {
    575             AcpiOsSleep (100);
    576         }
    577 
    578         AcpiOsTerminateDebugger ();
    579     }
    580 
    581     if (AcpiGbl_DbBuffer)
    582     {
    583         AcpiOsFree (AcpiGbl_DbBuffer);
    584         AcpiGbl_DbBuffer = NULL;
    585     }
    586 
    587     /* Ensure that debug output is now disabled */
    588 
    589     AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT;
    590 }
    591 
    592 ACPI_EXPORT_SYMBOL (AcpiTerminateDebugger)
    593 
    594 
    595 /*******************************************************************************
    596  *
    597  * FUNCTION:    AcpiSetDebuggerThreadId
    598  *
    599  * PARAMETERS:  ThreadId        - Debugger thread ID
    600  *
    601  * RETURN:      None
    602  *
    603  * DESCRIPTION: Set debugger thread ID
    604  *
    605  ******************************************************************************/
    606 
    607 void
    608 AcpiSetDebuggerThreadId (
    609     ACPI_THREAD_ID          ThreadId)
    610 {
    611     AcpiGbl_DbThreadId = ThreadId;
    612 }
    613 
    614 ACPI_EXPORT_SYMBOL (AcpiSetDebuggerThreadId)
    615