1 //===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/lldb-python.h" 11 12 #include "CommandObjectDisassemble.h" 13 14 // C Includes 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Core/AddressRange.h" 19 #include "lldb/Core/Disassembler.h" 20 #include "lldb/Core/SourceManager.h" 21 #include "lldb/Interpreter/Args.h" 22 #include "lldb/Interpreter/CommandCompletions.h" 23 #include "lldb/Interpreter/CommandInterpreter.h" 24 #include "lldb/Interpreter/CommandReturnObject.h" 25 #include "lldb/Interpreter/Options.h" 26 #include "lldb/Symbol/Function.h" 27 #include "lldb/Symbol/Symbol.h" 28 #include "lldb/Target/Process.h" 29 #include "lldb/Target/StackFrame.h" 30 #include "lldb/Target/Target.h" 31 32 #define DEFAULT_DISASM_BYTE_SIZE 32 33 #define DEFAULT_DISASM_NUM_INS 4 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 CommandObjectDisassemble::CommandOptions::CommandOptions (CommandInterpreter &interpreter) : 39 Options(interpreter), 40 num_lines_context(0), 41 num_instructions (0), 42 func_name(), 43 current_function (false), 44 start_addr(), 45 end_addr (), 46 at_pc (false), 47 frame_line (false), 48 plugin_name (), 49 flavor_string(), 50 arch(), 51 some_location_specified (false) 52 { 53 OptionParsingStarting(); 54 } 55 56 CommandObjectDisassemble::CommandOptions::~CommandOptions () 57 { 58 } 59 60 Error 61 CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg) 62 { 63 Error error; 64 65 const int short_option = m_getopt_table[option_idx].val; 66 67 bool success; 68 69 switch (short_option) 70 { 71 case 'm': 72 show_mixed = true; 73 break; 74 75 case 'C': 76 num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success); 77 if (!success) 78 error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg); 79 break; 80 81 case 'c': 82 num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success); 83 if (!success) 84 error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg); 85 break; 86 87 case 'b': 88 show_bytes = true; 89 break; 90 91 case 's': 92 { 93 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 94 start_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 95 if (start_addr != LLDB_INVALID_ADDRESS) 96 some_location_specified = true; 97 } 98 break; 99 case 'e': 100 { 101 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 102 end_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 103 if (end_addr != LLDB_INVALID_ADDRESS) 104 some_location_specified = true; 105 } 106 break; 107 case 'n': 108 func_name.assign (option_arg); 109 some_location_specified = true; 110 break; 111 112 case 'p': 113 at_pc = true; 114 some_location_specified = true; 115 break; 116 117 case 'l': 118 frame_line = true; 119 // Disassemble the current source line kind of implies showing mixed 120 // source code context. 121 show_mixed = true; 122 some_location_specified = true; 123 break; 124 125 case 'P': 126 plugin_name.assign (option_arg); 127 break; 128 129 case 'F': 130 { 131 Target *target = m_interpreter.GetExecutionContext().GetTargetPtr(); 132 if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 133 || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64) 134 { 135 flavor_string.assign (option_arg); 136 } 137 else 138 error.SetErrorStringWithFormat("Disassembler flavors are currently only supported for x86 and x86_64 targets."); 139 break; 140 } 141 case 'r': 142 raw = true; 143 break; 144 145 case 'f': 146 current_function = true; 147 some_location_specified = true; 148 break; 149 150 case 'a': 151 if (!arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get())) 152 arch.SetTriple (option_arg); 153 break; 154 155 default: 156 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); 157 break; 158 } 159 160 return error; 161 } 162 163 void 164 CommandObjectDisassemble::CommandOptions::OptionParsingStarting () 165 { 166 show_mixed = false; 167 show_bytes = false; 168 num_lines_context = 0; 169 num_instructions = 0; 170 func_name.clear(); 171 current_function = false; 172 at_pc = false; 173 frame_line = false; 174 start_addr = LLDB_INVALID_ADDRESS; 175 end_addr = LLDB_INVALID_ADDRESS; 176 raw = false; 177 plugin_name.clear(); 178 179 Target *target = m_interpreter.GetExecutionContext().GetTargetPtr(); 180 181 // This is a hack till we get the ability to specify features based on architecture. For now GetDisassemblyFlavor 182 // is really only valid for x86 (and for the llvm assembler plugin, but I'm papering over that since that is the 183 // only disassembler plugin we have... 184 if (target) 185 { 186 if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 187 || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64) 188 { 189 flavor_string.assign(target->GetDisassemblyFlavor()); 190 } 191 else 192 flavor_string.assign ("default"); 193 194 } 195 else 196 flavor_string.assign("default"); 197 198 arch.Clear(); 199 some_location_specified = false; 200 } 201 202 Error 203 CommandObjectDisassemble::CommandOptions::OptionParsingFinished () 204 { 205 if (!some_location_specified) 206 current_function = true; 207 return Error(); 208 209 } 210 211 const OptionDefinition* 212 CommandObjectDisassemble::CommandOptions::GetDefinitions () 213 { 214 return g_option_table; 215 } 216 217 OptionDefinition 218 CommandObjectDisassemble::CommandOptions::g_option_table[] = 219 { 220 { LLDB_OPT_SET_ALL, false, "bytes" , 'b', no_argument , NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."}, 221 { LLDB_OPT_SET_ALL, false, "context" , 'C', required_argument , NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."}, 222 { LLDB_OPT_SET_ALL, false, "mixed" , 'm', no_argument , NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."}, 223 { LLDB_OPT_SET_ALL, false, "raw" , 'r', no_argument , NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."}, 224 { LLDB_OPT_SET_ALL, false, "plugin" , 'P', required_argument , NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."}, 225 { LLDB_OPT_SET_ALL, false, "flavor" , 'F', required_argument , NULL, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. " 226 "Currently the only valid options are default, and for Intel" 227 " architectures, att and intel."}, 228 { LLDB_OPT_SET_ALL, false, "arch" , 'a', required_argument , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."}, 229 { LLDB_OPT_SET_1 | 230 LLDB_OPT_SET_2 , true , "start-address", 's', required_argument , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."}, 231 { LLDB_OPT_SET_1 , false, "end-address" , 'e', required_argument , NULL, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling."}, 232 { LLDB_OPT_SET_2 | 233 LLDB_OPT_SET_3 | 234 LLDB_OPT_SET_4 | 235 LLDB_OPT_SET_5 , false, "count" , 'c', required_argument , NULL, 0, eArgTypeNumLines, "Number of instructions to display."}, 236 { LLDB_OPT_SET_3 , false, "name" , 'n', required_argument , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, 237 "Disassemble entire contents of the given function name."}, 238 { LLDB_OPT_SET_4 , false, "frame" , 'f', no_argument , NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."}, 239 { LLDB_OPT_SET_5 , false, "pc" , 'p', no_argument , NULL, 0, eArgTypeNone, "Disassemble around the current pc."}, 240 { LLDB_OPT_SET_6 , false, "line" , 'l', no_argument , NULL, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there debug line table information, else disasemble around the pc."}, 241 { 0 , false, NULL , 0, 0 , NULL, 0, eArgTypeNone, NULL } 242 }; 243 244 245 246 //------------------------------------------------------------------------- 247 // CommandObjectDisassemble 248 //------------------------------------------------------------------------- 249 250 CommandObjectDisassemble::CommandObjectDisassemble (CommandInterpreter &interpreter) : 251 CommandObjectParsed (interpreter, 252 "disassemble", 253 "Disassemble bytes in the current function, or elsewhere in the executable program as specified by the user.", 254 "disassemble [<cmd-options>]"), 255 m_options (interpreter) 256 { 257 } 258 259 CommandObjectDisassemble::~CommandObjectDisassemble() 260 { 261 } 262 263 bool 264 CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result) 265 { 266 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 267 if (target == NULL) 268 { 269 result.AppendError ("invalid target, create a debug target using the 'target create' command"); 270 result.SetStatus (eReturnStatusFailed); 271 return false; 272 } 273 if (!m_options.arch.IsValid()) 274 m_options.arch = target->GetArchitecture(); 275 276 if (!m_options.arch.IsValid()) 277 { 278 result.AppendError ("use the --arch option or set the target architecure to disassemble"); 279 result.SetStatus (eReturnStatusFailed); 280 return false; 281 } 282 283 const char *plugin_name = m_options.GetPluginName (); 284 const char *flavor_string = m_options.GetFlavorString(); 285 286 DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name); 287 288 if (!disassembler) 289 { 290 if (plugin_name) 291 { 292 result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n", 293 plugin_name, 294 m_options.arch.GetArchitectureName()); 295 } 296 else 297 result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n", 298 m_options.arch.GetArchitectureName()); 299 result.SetStatus (eReturnStatusFailed); 300 return false; 301 } 302 else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string)) 303 result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string); 304 305 result.SetStatus (eReturnStatusSuccessFinishResult); 306 307 if (command.GetArgumentCount() != 0) 308 { 309 result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n"); 310 GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this); 311 result.SetStatus (eReturnStatusFailed); 312 return false; 313 } 314 315 if (m_options.show_mixed && m_options.num_lines_context == 0) 316 m_options.num_lines_context = 1; 317 318 // Always show the PC in the disassembly 319 uint32_t options = Disassembler::eOptionMarkPCAddress; 320 321 // Mark the source line for the current PC only if we are doing mixed source and assembly 322 if (m_options.show_mixed) 323 options |= Disassembler::eOptionMarkPCSourceLine; 324 325 if (m_options.show_bytes) 326 options |= Disassembler::eOptionShowBytes; 327 328 if (m_options.raw) 329 options |= Disassembler::eOptionRawOuput; 330 331 if (!m_options.func_name.empty()) 332 { 333 ConstString name(m_options.func_name.c_str()); 334 335 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 336 m_options.arch, 337 plugin_name, 338 flavor_string, 339 m_exe_ctx, 340 name, 341 NULL, // Module * 342 m_options.num_instructions, 343 m_options.show_mixed ? m_options.num_lines_context : 0, 344 options, 345 result.GetOutputStream())) 346 { 347 result.SetStatus (eReturnStatusSuccessFinishResult); 348 } 349 else 350 { 351 result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString()); 352 result.SetStatus (eReturnStatusFailed); 353 } 354 } 355 else 356 { 357 AddressRange range; 358 StackFrame *frame = m_exe_ctx.GetFramePtr(); 359 if (m_options.frame_line) 360 { 361 if (frame == NULL) 362 { 363 result.AppendError ("Cannot disassemble around the current line without a selected frame.\n"); 364 result.SetStatus (eReturnStatusFailed); 365 return false; 366 } 367 LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry); 368 if (pc_line_entry.IsValid()) 369 { 370 range = pc_line_entry.range; 371 } 372 else 373 { 374 m_options.at_pc = true; // No line entry, so just disassemble around the current pc 375 m_options.show_mixed = false; 376 } 377 } 378 else if (m_options.current_function) 379 { 380 if (frame == NULL) 381 { 382 result.AppendError ("Cannot disassemble around the current function without a selected frame.\n"); 383 result.SetStatus (eReturnStatusFailed); 384 return false; 385 } 386 Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol; 387 if (symbol) 388 { 389 range.GetBaseAddress() = symbol->GetAddress(); 390 range.SetByteSize(symbol->GetByteSize()); 391 } 392 } 393 394 // Did the "m_options.frame_line" find a valid range already? If so 395 // skip the rest... 396 if (range.GetByteSize() == 0) 397 { 398 if (m_options.at_pc) 399 { 400 if (frame == NULL) 401 { 402 result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n"); 403 result.SetStatus (eReturnStatusFailed); 404 return false; 405 } 406 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 407 if (m_options.num_instructions == 0) 408 { 409 // Disassembling at the PC always disassembles some number of instructions (not the whole function). 410 m_options.num_instructions = DEFAULT_DISASM_NUM_INS; 411 } 412 } 413 else 414 { 415 range.GetBaseAddress().SetOffset (m_options.start_addr); 416 if (range.GetBaseAddress().IsValid()) 417 { 418 if (m_options.end_addr != LLDB_INVALID_ADDRESS) 419 { 420 if (m_options.end_addr <= m_options.start_addr) 421 { 422 result.AppendErrorWithFormat ("End address before start address.\n"); 423 result.SetStatus (eReturnStatusFailed); 424 return false; 425 } 426 range.SetByteSize (m_options.end_addr - m_options.start_addr); 427 } 428 } 429 } 430 } 431 432 if (m_options.num_instructions != 0) 433 { 434 if (!range.GetBaseAddress().IsValid()) 435 { 436 // The default action is to disassemble the current frame function. 437 if (frame) 438 { 439 SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 440 if (sc.function) 441 range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress(); 442 else if (sc.symbol && sc.symbol->ValueIsAddress()) 443 range.GetBaseAddress() = sc.symbol->GetAddress(); 444 else 445 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 446 } 447 448 if (!range.GetBaseAddress().IsValid()) 449 { 450 result.AppendError ("invalid frame"); 451 result.SetStatus (eReturnStatusFailed); 452 return false; 453 } 454 } 455 456 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 457 m_options.arch, 458 plugin_name, 459 flavor_string, 460 m_exe_ctx, 461 range.GetBaseAddress(), 462 m_options.num_instructions, 463 m_options.show_mixed ? m_options.num_lines_context : 0, 464 options, 465 result.GetOutputStream())) 466 { 467 result.SetStatus (eReturnStatusSuccessFinishResult); 468 } 469 else 470 { 471 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); 472 result.SetStatus (eReturnStatusFailed); 473 } 474 } 475 else 476 { 477 if (!range.GetBaseAddress().IsValid()) 478 { 479 // The default action is to disassemble the current frame function. 480 if (frame) 481 { 482 SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 483 if (sc.function) 484 range = sc.function->GetAddressRange(); 485 else if (sc.symbol && sc.symbol->ValueIsAddress()) 486 { 487 range.GetBaseAddress() = sc.symbol->GetAddress(); 488 range.SetByteSize (sc.symbol->GetByteSize()); 489 } 490 else 491 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 492 } 493 else 494 { 495 result.AppendError ("invalid frame"); 496 result.SetStatus (eReturnStatusFailed); 497 return false; 498 } 499 } 500 if (range.GetByteSize() == 0) 501 range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); 502 503 if (Disassembler::Disassemble (m_interpreter.GetDebugger(), 504 m_options.arch, 505 plugin_name, 506 flavor_string, 507 m_exe_ctx, 508 range, 509 m_options.num_instructions, 510 m_options.show_mixed ? m_options.num_lines_context : 0, 511 options, 512 result.GetOutputStream())) 513 { 514 result.SetStatus (eReturnStatusSuccessFinishResult); 515 } 516 else 517 { 518 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr); 519 result.SetStatus (eReturnStatusFailed); 520 } 521 } 522 } 523 524 return result.Succeeded(); 525 } 526