text: /******************************************************************************
   *
   * Module Name: dsdebug - Parser/Interpreter interface - debugging
   *
   *****************************************************************************/
  
  /*
   * Copyright (C) 2000 - 2017, Intel Corp.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions, and the following disclaimer,
   *    without modification.
   * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   *    substantially similar to the "NO WARRANTY" disclaimer below
   *    ("Disclaimer") and any redistribution must be conditioned upon
   *    including a substantially similar Disclaimer requirement for further
   *    binary redistribution.
   * 3. Neither the names of the above-listed copyright holders nor the names
   *    of any contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   * Alternatively, this software may be distributed under the terms of the
   * GNU General Public License ("GPL") version 2 as published by the Free
   * Software Foundation.
   *
   * NO WARRANTY
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGES.
   */
  
  #include <acpi/acpi.h>
  #include "accommon.h"
  #include "acdispat.h"
  #include "acnamesp.h"
  #ifdef ACPI_DISASSEMBLER
  #include "acdisasm.h"
  #endif
  #include "acinterp.h"
  
  #define _COMPONENT          ACPI_DISPATCHER
  ACPI_MODULE_NAME("dsdebug")
  
  #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
  /* Local prototypes */
  static void
  acpi_ds_print_node_pathname(struct acpi_namespace_node *node,
  			    const char *message);
  
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ds_print_node_pathname
   *
   * PARAMETERS:  node            - Object
   *              message         - Prefix message
   *
   * DESCRIPTION: Print an object's full namespace pathname
   *              Manages allocation/freeing of a pathname buffer
   *
   ******************************************************************************/
  
  static void
  acpi_ds_print_node_pathname(struct acpi_namespace_node *node,
  			    const char *message)
  {
  	struct acpi_buffer buffer;
  	acpi_status status;
  
  	ACPI_FUNCTION_TRACE(ds_print_node_pathname);
  
  	if (!node) {
  		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]"));
  		return_VOID;
  	}
  
  	/* Convert handle to full pathname and print it (with supplied message) */
  
  	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
  
  	status = acpi_ns_handle_to_pathname(node, &buffer, TRUE);
  	if (ACPI_SUCCESS(status)) {
  		if (message) {
  			ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ",
  					      message));
  		}
  
  		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)",
  				      (char *)buffer.pointer, node));
  		ACPI_FREE(buffer.pointer);
  	}
  
  	return_VOID;
  }
  
  /*******************************************************************************
   *
   * FUNCTION:    acpi_ds_dump_method_stack
   *
   * PARAMETERS:  status          - Method execution status
   *              walk_state      - Current state of the parse tree walk
   *              op              - Executing parse op
   *
   * RETURN:      None
   *
   * DESCRIPTION: Called when a method has been aborted because of an error.
   *              Dumps the method execution stack.
   *
   ******************************************************************************/
  
  void
  acpi_ds_dump_method_stack(acpi_status status,
  			  struct acpi_walk_state *walk_state,
  			  union acpi_parse_object *op)
  {
  	union acpi_parse_object *next;
  	struct acpi_thread_state *thread;
  	struct acpi_walk_state *next_walk_state;
  	struct acpi_namespace_node *previous_method = NULL;
  	union acpi_operand_object *method_desc;
  
  	ACPI_FUNCTION_TRACE(ds_dump_method_stack);
  
  	/* Ignore control codes, they are not errors */
  
  	if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) {
  		return_VOID;
  	}
  
  	/* We may be executing a deferred opcode */
  
  	if (walk_state->deferred_node) {
  		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
  				  "Executing subtree for Buffer/Package/Region\n"));
  		return_VOID;
  	}
  
  	/*
  	 * If there is no Thread, we are not actually executing a method.
  	 * This can happen when the iASL compiler calls the interpreter
  	 * to perform constant folding.
  	 */
  	thread = walk_state->thread;
  	if (!thread) {
  		return_VOID;
  	}
  
  	/* Display exception and method name */
  
  	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
  			  "\n**** Exception %s during execution of method ",
  			  acpi_format_exception(status)));
  
  	acpi_ds_print_node_pathname(walk_state->method_node, NULL);
  
  	/* Display stack of executing methods */
  
  	ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH,
  			      "\n\nMethod Execution Stack:\n"));
  	next_walk_state = thread->walk_state_list;
  
  	/* Walk list of linked walk states */
  
  	while (next_walk_state) {
  		method_desc = next_walk_state->method_desc;
  		if (method_desc) {
  			acpi_ex_stop_trace_method((struct acpi_namespace_node *)
  						  method_desc->method.node,
  						  method_desc, walk_state);
  		}
  
  		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
  				  "    Method [%4.4s] executing: ",
  				  acpi_ut_get_node_name(next_walk_state->
  							method_node)));
  
  		/* First method is the currently executing method */
  
  		if (next_walk_state == walk_state) {
  			if (op) {
  
  				/* Display currently executing ASL statement */
  
  				next = op->common.next;
  				op->common.next = NULL;
  
  #ifdef ACPI_DISASSEMBLER
  				acpi_os_printf("Failed at ");
  				acpi_dm_disassemble(next_walk_state, op,
  						    ACPI_UINT32_MAX);
  #endif
  				op->common.next = next;
  			}
  		} else {
  			/*
  			 * This method has called another method
  			 * NOTE: the method call parse subtree is already deleted at
  			 * this point, so we cannot disassemble the method invocation.
  			 */
  			ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH,
  					      "Call to method "));
  			acpi_ds_print_node_pathname(previous_method, NULL);
  		}
  
  		previous_method = next_walk_state->method_node;
  		next_walk_state = next_walk_state->next;
  		ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n"));
  	}
  
  	return_VOID;
  }
  
  #else
  void
  acpi_ds_dump_method_stack(acpi_status status,
  			  struct acpi_walk_state *walk_state,
  			  union acpi_parse_object *op)
  {
  	return;
  }
  
  #endif
  