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