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