1 /******************************************************************************* 2 * 3 * Module Name: dbmethod - Debug commands for control methods 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/acpi.h> 45 #include "accommon.h" 46 #include "acdispat.h" 47 #include "acnamesp.h" 48 #include "acdebug.h" 49 #include "acparser.h" 50 #include "acpredef.h" 51 52 #define _COMPONENT ACPI_CA_DEBUGGER 53 ACPI_MODULE_NAME("dbmethod") 54 55 /******************************************************************************* 56 * 57 * FUNCTION: acpi_db_set_method_breakpoint 58 * 59 * PARAMETERS: location - AML offset of breakpoint 60 * walk_state - Current walk info 61 * op - Current Op (from parse walk) 62 * 63 * RETURN: None 64 * 65 * DESCRIPTION: Set a breakpoint in a control method at the specified 66 * AML offset 67 * 68 ******************************************************************************/ 69 void 70 acpi_db_set_method_breakpoint(char *location, 71 struct acpi_walk_state *walk_state, 72 union acpi_parse_object *op) 73 { 74 u32 address; 75 u32 aml_offset; 76 77 if (!op) { 78 acpi_os_printf("There is no method currently executing\n"); 79 return; 80 } 81 82 /* Get and verify the breakpoint address */ 83 84 address = strtoul(location, NULL, 16); 85 aml_offset = (u32)ACPI_PTR_DIFF(op->common.aml, 86 walk_state->parser_state.aml_start); 87 if (address <= aml_offset) { 88 acpi_os_printf("Breakpoint %X is beyond current address %X\n", 89 address, aml_offset); 90 } 91 92 /* Save breakpoint in current walk */ 93 94 walk_state->user_breakpoint = address; 95 acpi_os_printf("Breakpoint set at AML offset %X\n", address); 96 } 97 98 /******************************************************************************* 99 * 100 * FUNCTION: acpi_db_set_method_call_breakpoint 101 * 102 * PARAMETERS: op - Current Op (from parse walk) 103 * 104 * RETURN: None 105 * 106 * DESCRIPTION: Set a breakpoint in a control method at the specified 107 * AML offset 108 * 109 ******************************************************************************/ 110 111 void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op) 112 { 113 114 if (!op) { 115 acpi_os_printf("There is no method currently executing\n"); 116 return; 117 } 118 119 acpi_gbl_step_to_next_call = TRUE; 120 } 121 122 /******************************************************************************* 123 * 124 * FUNCTION: acpi_db_set_method_data 125 * 126 * PARAMETERS: type_arg - L for local, A for argument 127 * index_arg - which one 128 * value_arg - Value to set. 129 * 130 * RETURN: None 131 * 132 * DESCRIPTION: Set a local or argument for the running control method. 133 * NOTE: only object supported is Number. 134 * 135 ******************************************************************************/ 136 137 void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg) 138 { 139 char type; 140 u32 index; 141 u32 value; 142 struct acpi_walk_state *walk_state; 143 union acpi_operand_object *obj_desc; 144 acpi_status status; 145 struct acpi_namespace_node *node; 146 147 /* Validate type_arg */ 148 149 acpi_ut_strupr(type_arg); 150 type = type_arg[0]; 151 if ((type != 'L') && (type != 'A') && (type != 'N')) { 152 acpi_os_printf("Invalid SET operand: %s\n", type_arg); 153 return; 154 } 155 156 value = strtoul(value_arg, NULL, 16); 157 158 if (type == 'N') { 159 node = acpi_db_convert_to_node(index_arg); 160 if (!node) { 161 return; 162 } 163 164 if (node->type != ACPI_TYPE_INTEGER) { 165 acpi_os_printf("Can only set Integer nodes\n"); 166 return; 167 } 168 obj_desc = node->object; 169 obj_desc->integer.value = value; 170 return; 171 } 172 173 /* Get the index and value */ 174 175 index = strtoul(index_arg, NULL, 16); 176 177 walk_state = acpi_ds_get_current_walk_state(acpi_gbl_current_walk_list); 178 if (!walk_state) { 179 acpi_os_printf("There is no method currently executing\n"); 180 return; 181 } 182 183 /* Create and initialize the new object */ 184 185 obj_desc = acpi_ut_create_integer_object((u64)value); 186 if (!obj_desc) { 187 acpi_os_printf("Could not create an internal object\n"); 188 return; 189 } 190 191 /* Store the new object into the target */ 192 193 switch (type) { 194 case 'A': 195 196 /* Set a method argument */ 197 198 if (index > ACPI_METHOD_MAX_ARG) { 199 acpi_os_printf("Arg%u - Invalid argument name\n", 200 index); 201 goto cleanup; 202 } 203 204 status = acpi_ds_store_object_to_local(ACPI_REFCLASS_ARG, 205 index, obj_desc, 206 walk_state); 207 if (ACPI_FAILURE(status)) { 208 goto cleanup; 209 } 210 211 obj_desc = walk_state->arguments[index].object; 212 213 acpi_os_printf("Arg%u: ", index); 214 acpi_db_display_internal_object(obj_desc, walk_state); 215 break; 216 217 case 'L': 218 219 /* Set a method local */ 220 221 if (index > ACPI_METHOD_MAX_LOCAL) { 222 acpi_os_printf 223 ("Local%u - Invalid local variable name\n", index); 224 goto cleanup; 225 } 226 227 status = acpi_ds_store_object_to_local(ACPI_REFCLASS_LOCAL, 228 index, obj_desc, 229 walk_state); 230 if (ACPI_FAILURE(status)) { 231 goto cleanup; 232 } 233 234 obj_desc = walk_state->local_variables[index].object; 235 236 acpi_os_printf("Local%u: ", index); 237 acpi_db_display_internal_object(obj_desc, walk_state); 238 break; 239 240 default: 241 242 break; 243 } 244 245 cleanup: 246 acpi_ut_remove_reference(obj_desc); 247 } 248 249 /******************************************************************************* 250 * 251 * FUNCTION: acpi_db_disassemble_aml 252 * 253 * PARAMETERS: statements - Number of statements to disassemble 254 * op - Current Op (from parse walk) 255 * 256 * RETURN: None 257 * 258 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number 259 * of statements specified. 260 * 261 ******************************************************************************/ 262 263 void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op) 264 { 265 u32 num_statements = 8; 266 267 if (!op) { 268 acpi_os_printf("There is no method currently executing\n"); 269 return; 270 } 271 272 if (statements) { 273 num_statements = strtoul(statements, NULL, 0); 274 } 275 #ifdef ACPI_DISASSEMBLER 276 acpi_dm_disassemble(NULL, op, num_statements); 277 #endif 278 } 279 280 /******************************************************************************* 281 * 282 * FUNCTION: acpi_db_disassemble_method 283 * 284 * PARAMETERS: name - Name of control method 285 * 286 * RETURN: None 287 * 288 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number 289 * of statements specified. 290 * 291 ******************************************************************************/ 292 293 acpi_status acpi_db_disassemble_method(char *name) 294 { 295 acpi_status status; 296 union acpi_parse_object *op; 297 struct acpi_walk_state *walk_state; 298 union acpi_operand_object *obj_desc; 299 struct acpi_namespace_node *method; 300 301 method = acpi_db_convert_to_node(name); 302 if (!method) { 303 return (AE_BAD_PARAMETER); 304 } 305 306 if (method->type != ACPI_TYPE_METHOD) { 307 ACPI_ERROR((AE_INFO, "%s (%s): Object must be a control method", 308 name, acpi_ut_get_type_name(method->type))); 309 return (AE_BAD_PARAMETER); 310 } 311 312 obj_desc = method->object; 313 314 op = acpi_ps_create_scope_op(obj_desc->method.aml_start); 315 if (!op) { 316 return (AE_NO_MEMORY); 317 } 318 319 /* Create and initialize a new walk state */ 320 321 walk_state = acpi_ds_create_walk_state(0, op, NULL, NULL); 322 if (!walk_state) { 323 return (AE_NO_MEMORY); 324 } 325 326 status = acpi_ds_init_aml_walk(walk_state, op, NULL, 327 obj_desc->method.aml_start, 328 obj_desc->method.aml_length, NULL, 329 ACPI_IMODE_LOAD_PASS1); 330 if (ACPI_FAILURE(status)) { 331 return (status); 332 } 333 334 status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); 335 walk_state->owner_id = obj_desc->method.owner_id; 336 337 /* Push start scope on scope stack and make it current */ 338 339 status = acpi_ds_scope_stack_push(method, method->type, walk_state); 340 if (ACPI_FAILURE(status)) { 341 return (status); 342 } 343 344 /* Parse the entire method AML including deferred operators */ 345 346 walk_state->parse_flags &= ~ACPI_PARSE_DELETE_TREE; 347 walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE; 348 349 status = acpi_ps_parse_aml(walk_state); 350 351 #ifdef ACPI_DISASSEMBLER 352 (void)acpi_dm_parse_deferred_ops(op); 353 354 /* Now we can disassemble the method */ 355 356 acpi_gbl_dm_opt_verbose = FALSE; 357 acpi_dm_disassemble(NULL, op, 0); 358 acpi_gbl_dm_opt_verbose = TRUE; 359 #endif 360 361 acpi_ps_delete_parse_tree(op); 362 363 /* Method cleanup */ 364 365 acpi_ns_delete_namespace_subtree(method); 366 acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id); 367 acpi_ut_release_owner_id(&obj_desc->method.owner_id); 368 return (AE_OK); 369 } 370