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