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