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