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