Sync ACPICA with Intel's version 20161222.
[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 - 2016, 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
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_BREAK_POINT_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 ("\n[AmlDebug] 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     Status = AcpiDbStartCommand (WalkState, Op);
409
410     /* User commands complete, continue execution of the interrupted method */
411
412     return (Status);
413 }
414
415
416 /*******************************************************************************
417  *
418  * FUNCTION:    AcpiInitializeDebugger
419  *
420  * PARAMETERS:  None
421  *
422  * RETURN:      Status
423  *
424  * DESCRIPTION: Init and start debugger
425  *
426  ******************************************************************************/
427
428 ACPI_STATUS
429 AcpiInitializeDebugger (
430     void)
431 {
432     ACPI_STATUS             Status;
433
434
435     ACPI_FUNCTION_TRACE (AcpiInitializeDebugger);
436
437
438     /* Init globals */
439
440     AcpiGbl_DbBuffer            = NULL;
441     AcpiGbl_DbFilename          = NULL;
442     AcpiGbl_DbOutputToFile      = FALSE;
443
444     AcpiGbl_DbDebugLevel        = ACPI_LV_VERBOSITY2;
445     AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES;
446     AcpiGbl_DbOutputFlags       = ACPI_DB_CONSOLE_OUTPUT;
447
448     AcpiGbl_DbOpt_NoIniMethods  = FALSE;
449
450     AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE);
451     if (!AcpiGbl_DbBuffer)
452     {
453         return_ACPI_STATUS (AE_NO_MEMORY);
454     }
455     memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE);
456
457     /* Initial scope is the root */
458
459     AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX;
460     AcpiGbl_DbScopeBuf [1] =  0;
461     AcpiGbl_DbScopeNode = AcpiGbl_RootNode;
462
463     /* Initialize user commands loop */
464
465     AcpiGbl_DbTerminateLoop = FALSE;
466
467     /*
468      * If configured for multi-thread support, the debug executor runs in
469      * a separate thread so that the front end can be in another address
470      * space, environment, or even another machine.
471      */
472     if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED)
473     {
474         /* These were created with one unit, grab it */
475
476         Status = AcpiOsInitializeDebugger ();
477         if (ACPI_FAILURE (Status))
478         {
479             AcpiOsPrintf ("Could not get debugger mutex\n");
480             return_ACPI_STATUS (Status);
481         }
482
483         /* Create the debug execution thread to execute commands */
484
485         AcpiGbl_DbThreadsTerminated = FALSE;
486         Status = AcpiOsExecute (OSL_DEBUGGER_MAIN_THREAD,
487             AcpiDbExecuteThread, NULL);
488         if (ACPI_FAILURE (Status))
489         {
490             ACPI_EXCEPTION ((AE_INFO, Status,
491                 "Could not start debugger thread"));
492             AcpiGbl_DbThreadsTerminated = TRUE;
493             return_ACPI_STATUS (Status);
494         }
495     }
496     else
497     {
498         AcpiGbl_DbThreadId = AcpiOsGetThreadId ();
499     }
500
501     return_ACPI_STATUS (AE_OK);
502 }
503
504 ACPI_EXPORT_SYMBOL (AcpiInitializeDebugger)
505
506
507 /*******************************************************************************
508  *
509  * FUNCTION:    AcpiTerminateDebugger
510  *
511  * PARAMETERS:  None
512  *
513  * RETURN:      None
514  *
515  * DESCRIPTION: Stop debugger
516  *
517  ******************************************************************************/
518
519 void
520 AcpiTerminateDebugger (
521     void)
522 {
523
524     /* Terminate the AML Debugger */
525
526     AcpiGbl_DbTerminateLoop = TRUE;
527
528     if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED)
529     {
530         /* Wait the AML Debugger threads */
531
532         while (!AcpiGbl_DbThreadsTerminated)
533         {
534             AcpiOsSleep (100);
535         }
536
537         AcpiOsTerminateDebugger ();
538     }
539
540     if (AcpiGbl_DbBuffer)
541     {
542         AcpiOsFree (AcpiGbl_DbBuffer);
543         AcpiGbl_DbBuffer = NULL;
544     }
545
546     /* Ensure that debug output is now disabled */
547
548     AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT;
549 }
550
551 ACPI_EXPORT_SYMBOL (AcpiTerminateDebugger)
552
553
554 /*******************************************************************************
555  *
556  * FUNCTION:    AcpiSetDebuggerThreadId
557  *
558  * PARAMETERS:  ThreadId        - Debugger thread ID
559  *
560  * RETURN:      None
561  *
562  * DESCRIPTION: Set debugger thread ID
563  *
564  ******************************************************************************/
565
566 void
567 AcpiSetDebuggerThreadId (
568     ACPI_THREAD_ID          ThreadId)
569 {
570     AcpiGbl_DbThreadId = ThreadId;
571 }
572
573 ACPI_EXPORT_SYMBOL (AcpiSetDebuggerThreadId)
574
575 #endif /* ACPI_DEBUGGER */