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