1 //===-- Disassembler.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/Core/Disassembler.h" 11 12 // C Includes 13 // C++ Includes 14 #include <cstdio> 15 #include <cstring> 16 17 // Other libraries and framework includes 18 // Project includes 19 #include "lldb/Core/DataBufferHeap.h" 20 #include "lldb/Core/DataExtractor.h" 21 #include "lldb/Core/Debugger.h" 22 #include "lldb/Core/EmulateInstruction.h" 23 #include "lldb/Core/Error.h" 24 #include "lldb/Core/Module.h" 25 #include "lldb/Core/PluginManager.h" 26 #include "lldb/Core/RegularExpression.h" 27 #include "lldb/Core/Timer.h" 28 #include "lldb/Host/FileSystem.h" 29 #include "lldb/Interpreter/OptionValue.h" 30 #include "lldb/Interpreter/OptionValueArray.h" 31 #include "lldb/Interpreter/OptionValueDictionary.h" 32 #include "lldb/Interpreter/OptionValueRegex.h" 33 #include "lldb/Interpreter/OptionValueString.h" 34 #include "lldb/Interpreter/OptionValueUInt64.h" 35 #include "lldb/Symbol/Function.h" 36 #include "lldb/Symbol/ObjectFile.h" 37 #include "lldb/Target/ExecutionContext.h" 38 #include "lldb/Target/Process.h" 39 #include "lldb/Target/SectionLoadList.h" 40 #include "lldb/Target/StackFrame.h" 41 #include "lldb/Target/Target.h" 42 #include "lldb/lldb-private.h" 43 44 #define DEFAULT_DISASM_BYTE_SIZE 32 45 46 using namespace lldb; 47 using namespace lldb_private; 48 49 DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch, 50 const char *flavor, 51 const char *plugin_name) { 52 Timer scoped_timer(LLVM_PRETTY_FUNCTION, 53 "Disassembler::FindPlugin (arch = %s, plugin_name = %s)", 54 arch.GetArchitectureName(), plugin_name); 55 56 DisassemblerCreateInstance create_callback = nullptr; 57 58 if (plugin_name) { 59 ConstString const_plugin_name(plugin_name); 60 create_callback = PluginManager::GetDisassemblerCreateCallbackForPluginName( 61 const_plugin_name); 62 if (create_callback) { 63 DisassemblerSP disassembler_sp(create_callback(arch, flavor)); 64 65 if (disassembler_sp) 66 return disassembler_sp; 67 } 68 } else { 69 for (uint32_t idx = 0; 70 (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex( 71 idx)) != nullptr; 72 ++idx) { 73 DisassemblerSP disassembler_sp(create_callback(arch, flavor)); 74 75 if (disassembler_sp) 76 return disassembler_sp; 77 } 78 } 79 return DisassemblerSP(); 80 } 81 82 DisassemblerSP Disassembler::FindPluginForTarget(const TargetSP target_sp, 83 const ArchSpec &arch, 84 const char *flavor, 85 const char *plugin_name) { 86 if (target_sp && flavor == nullptr) { 87 // FIXME - we don't have the mechanism in place to do per-architecture 88 // settings. But since we know that for now 89 // we only support flavors on x86 & x86_64, 90 if (arch.GetTriple().getArch() == llvm::Triple::x86 || 91 arch.GetTriple().getArch() == llvm::Triple::x86_64) 92 flavor = target_sp->GetDisassemblyFlavor(); 93 } 94 return FindPlugin(arch, flavor, plugin_name); 95 } 96 97 static void ResolveAddress(const ExecutionContext &exe_ctx, const Address &addr, 98 Address &resolved_addr) { 99 if (!addr.IsSectionOffset()) { 100 // If we weren't passed in a section offset address range, 101 // try and resolve it to something 102 Target *target = exe_ctx.GetTargetPtr(); 103 if (target) { 104 if (target->GetSectionLoadList().IsEmpty()) { 105 target->GetImages().ResolveFileAddress(addr.GetOffset(), resolved_addr); 106 } else { 107 target->GetSectionLoadList().ResolveLoadAddress(addr.GetOffset(), 108 resolved_addr); 109 } 110 // We weren't able to resolve the address, just treat it as a 111 // raw address 112 if (resolved_addr.IsValid()) 113 return; 114 } 115 } 116 resolved_addr = addr; 117 } 118 119 size_t Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, 120 const char *plugin_name, const char *flavor, 121 const ExecutionContext &exe_ctx, 122 SymbolContextList &sc_list, 123 uint32_t num_instructions, 124 bool mixed_source_and_assembly, 125 uint32_t num_mixed_context_lines, 126 uint32_t options, Stream &strm) { 127 size_t success_count = 0; 128 const size_t count = sc_list.GetSize(); 129 SymbolContext sc; 130 AddressRange range; 131 const uint32_t scope = 132 eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol; 133 const bool use_inline_block_range = true; 134 for (size_t i = 0; i < count; ++i) { 135 if (!sc_list.GetContextAtIndex(i, sc)) 136 break; 137 for (uint32_t range_idx = 0; 138 sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); 139 ++range_idx) { 140 if (Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, range, 141 num_instructions, mixed_source_and_assembly, 142 num_mixed_context_lines, options, strm)) { 143 ++success_count; 144 strm.EOL(); 145 } 146 } 147 } 148 return success_count; 149 } 150 151 bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, 152 const char *plugin_name, const char *flavor, 153 const ExecutionContext &exe_ctx, 154 const ConstString &name, Module *module, 155 uint32_t num_instructions, 156 bool mixed_source_and_assembly, 157 uint32_t num_mixed_context_lines, 158 uint32_t options, Stream &strm) { 159 SymbolContextList sc_list; 160 if (name) { 161 const bool include_symbols = true; 162 const bool include_inlines = true; 163 if (module) { 164 module->FindFunctions(name, nullptr, eFunctionNameTypeAuto, 165 include_symbols, include_inlines, true, sc_list); 166 } else if (exe_ctx.GetTargetPtr()) { 167 exe_ctx.GetTargetPtr()->GetImages().FindFunctions( 168 name, eFunctionNameTypeAuto, include_symbols, include_inlines, false, 169 sc_list); 170 } 171 } 172 173 if (sc_list.GetSize()) { 174 return Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, sc_list, 175 num_instructions, mixed_source_and_assembly, 176 num_mixed_context_lines, options, strm); 177 } 178 return false; 179 } 180 181 lldb::DisassemblerSP Disassembler::DisassembleRange( 182 const ArchSpec &arch, const char *plugin_name, const char *flavor, 183 const ExecutionContext &exe_ctx, const AddressRange &range, 184 bool prefer_file_cache) { 185 lldb::DisassemblerSP disasm_sp; 186 if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid()) { 187 disasm_sp = Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, 188 flavor, plugin_name); 189 190 if (disasm_sp) { 191 size_t bytes_disassembled = disasm_sp->ParseInstructions( 192 &exe_ctx, range, nullptr, prefer_file_cache); 193 if (bytes_disassembled == 0) 194 disasm_sp.reset(); 195 } 196 } 197 return disasm_sp; 198 } 199 200 lldb::DisassemblerSP 201 Disassembler::DisassembleBytes(const ArchSpec &arch, const char *plugin_name, 202 const char *flavor, const Address &start, 203 const void *src, size_t src_len, 204 uint32_t num_instructions, bool data_from_file) { 205 lldb::DisassemblerSP disasm_sp; 206 207 if (src) { 208 disasm_sp = Disassembler::FindPlugin(arch, flavor, plugin_name); 209 210 if (disasm_sp) { 211 DataExtractor data(src, src_len, arch.GetByteOrder(), 212 arch.GetAddressByteSize()); 213 214 (void)disasm_sp->DecodeInstructions(start, data, 0, num_instructions, 215 false, data_from_file); 216 } 217 } 218 219 return disasm_sp; 220 } 221 222 bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, 223 const char *plugin_name, const char *flavor, 224 const ExecutionContext &exe_ctx, 225 const AddressRange &disasm_range, 226 uint32_t num_instructions, 227 bool mixed_source_and_assembly, 228 uint32_t num_mixed_context_lines, 229 uint32_t options, Stream &strm) { 230 if (disasm_range.GetByteSize()) { 231 lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget( 232 exe_ctx.GetTargetSP(), arch, flavor, plugin_name)); 233 234 if (disasm_sp) { 235 AddressRange range; 236 ResolveAddress(exe_ctx, disasm_range.GetBaseAddress(), 237 range.GetBaseAddress()); 238 range.SetByteSize(disasm_range.GetByteSize()); 239 const bool prefer_file_cache = false; 240 size_t bytes_disassembled = disasm_sp->ParseInstructions( 241 &exe_ctx, range, &strm, prefer_file_cache); 242 if (bytes_disassembled == 0) 243 return false; 244 245 return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx, 246 num_instructions, mixed_source_and_assembly, 247 num_mixed_context_lines, options, strm); 248 } 249 } 250 return false; 251 } 252 253 bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, 254 const char *plugin_name, const char *flavor, 255 const ExecutionContext &exe_ctx, 256 const Address &start_address, 257 uint32_t num_instructions, 258 bool mixed_source_and_assembly, 259 uint32_t num_mixed_context_lines, 260 uint32_t options, Stream &strm) { 261 if (num_instructions > 0) { 262 lldb::DisassemblerSP disasm_sp(Disassembler::FindPluginForTarget( 263 exe_ctx.GetTargetSP(), arch, flavor, plugin_name)); 264 if (disasm_sp) { 265 Address addr; 266 ResolveAddress(exe_ctx, start_address, addr); 267 const bool prefer_file_cache = false; 268 size_t bytes_disassembled = disasm_sp->ParseInstructions( 269 &exe_ctx, addr, num_instructions, prefer_file_cache); 270 if (bytes_disassembled == 0) 271 return false; 272 return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx, 273 num_instructions, mixed_source_and_assembly, 274 num_mixed_context_lines, options, strm); 275 } 276 } 277 return false; 278 } 279 280 Disassembler::SourceLine 281 Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) { 282 SourceLine decl_line; 283 if (sc.function && sc.line_entry.IsValid()) { 284 LineEntry prologue_end_line = sc.line_entry; 285 FileSpec func_decl_file; 286 uint32_t func_decl_line; 287 sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line); 288 if (func_decl_file == prologue_end_line.file || 289 func_decl_file == prologue_end_line.original_file) { 290 decl_line.file = func_decl_file; 291 decl_line.line = func_decl_line; 292 } 293 } 294 return decl_line; 295 } 296 297 void Disassembler::AddLineToSourceLineTables( 298 SourceLine &line, 299 std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) { 300 if (line.IsValid()) { 301 auto source_lines_seen_pos = source_lines_seen.find(line.file); 302 if (source_lines_seen_pos == source_lines_seen.end()) { 303 std::set<uint32_t> lines; 304 lines.insert(line.line); 305 source_lines_seen.emplace(line.file, lines); 306 } else { 307 source_lines_seen_pos->second.insert(line.line); 308 } 309 } 310 } 311 312 bool Disassembler::ElideMixedSourceAndDisassemblyLine( 313 const ExecutionContext &exe_ctx, const SymbolContext &sc, 314 SourceLine &line) { 315 316 // TODO: should we also check target.process.thread.step-avoid-libraries ? 317 318 const RegularExpression *avoid_regex = nullptr; 319 320 // Skip any line #0 entries - they are implementation details 321 if (line.line == 0) 322 return false; 323 324 ThreadSP thread_sp = exe_ctx.GetThreadSP(); 325 if (thread_sp) { 326 avoid_regex = thread_sp->GetSymbolsToAvoidRegexp(); 327 } else { 328 TargetSP target_sp = exe_ctx.GetTargetSP(); 329 if (target_sp) { 330 Error error; 331 OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue( 332 &exe_ctx, "target.process.thread.step-avoid-regexp", false, error); 333 if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) { 334 OptionValueRegex *re = value_sp->GetAsRegex(); 335 if (re) { 336 avoid_regex = re->GetCurrentValue(); 337 } 338 } 339 } 340 } 341 if (avoid_regex && sc.symbol != nullptr) { 342 const char *function_name = 343 sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments) 344 .GetCString(); 345 if (function_name) { 346 RegularExpression::Match regex_match(1); 347 if (avoid_regex->Execute(function_name, ®ex_match)) { 348 // skip this source line 349 return true; 350 } 351 } 352 } 353 // don't skip this source line 354 return false; 355 } 356 357 bool Disassembler::PrintInstructions(Disassembler *disasm_ptr, 358 Debugger &debugger, const ArchSpec &arch, 359 const ExecutionContext &exe_ctx, 360 uint32_t num_instructions, 361 bool mixed_source_and_assembly, 362 uint32_t num_mixed_context_lines, 363 uint32_t options, Stream &strm) { 364 // We got some things disassembled... 365 size_t num_instructions_found = disasm_ptr->GetInstructionList().GetSize(); 366 367 if (num_instructions > 0 && num_instructions < num_instructions_found) 368 num_instructions_found = num_instructions; 369 370 const uint32_t max_opcode_byte_size = 371 disasm_ptr->GetInstructionList().GetMaxOpcocdeByteSize(); 372 SymbolContext sc; 373 SymbolContext prev_sc; 374 AddressRange current_source_line_range; 375 const Address *pc_addr_ptr = nullptr; 376 StackFrame *frame = exe_ctx.GetFramePtr(); 377 378 TargetSP target_sp(exe_ctx.GetTargetSP()); 379 SourceManager &source_manager = 380 target_sp ? target_sp->GetSourceManager() : debugger.GetSourceManager(); 381 382 if (frame) { 383 pc_addr_ptr = &frame->GetFrameCodeAddress(); 384 } 385 const uint32_t scope = 386 eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol; 387 const bool use_inline_block_range = false; 388 389 const FormatEntity::Entry *disassembly_format = nullptr; 390 FormatEntity::Entry format; 391 if (exe_ctx.HasTargetScope()) { 392 disassembly_format = 393 exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat(); 394 } else { 395 FormatEntity::Parse("${addr}: ", format); 396 disassembly_format = &format; 397 } 398 399 // First pass: step through the list of instructions, 400 // find how long the initial addresses strings are, insert padding 401 // in the second pass so the opcodes all line up nicely. 402 403 // Also build up the source line mapping if this is mixed source & assembly 404 // mode. 405 // Calculate the source line for each assembly instruction (eliding inlined 406 // functions 407 // which the user wants to skip). 408 409 std::map<FileSpec, std::set<uint32_t>> source_lines_seen; 410 Symbol *previous_symbol = nullptr; 411 412 size_t address_text_size = 0; 413 for (size_t i = 0; i < num_instructions_found; ++i) { 414 Instruction *inst = 415 disasm_ptr->GetInstructionList().GetInstructionAtIndex(i).get(); 416 if (inst) { 417 const Address &addr = inst->GetAddress(); 418 ModuleSP module_sp(addr.GetModule()); 419 if (module_sp) { 420 const uint32_t resolve_mask = eSymbolContextFunction | 421 eSymbolContextSymbol | 422 eSymbolContextLineEntry; 423 uint32_t resolved_mask = 424 module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc); 425 if (resolved_mask) { 426 StreamString strmstr; 427 Debugger::FormatDisassemblerAddress(disassembly_format, &sc, nullptr, 428 &exe_ctx, &addr, strmstr); 429 size_t cur_line = strmstr.GetSizeOfLastLine(); 430 if (cur_line > address_text_size) 431 address_text_size = cur_line; 432 433 // Add entries to our "source_lines_seen" map+set which list which 434 // sources lines occur in this disassembly session. We will print 435 // lines of context around a source line, but we don't want to print 436 // a source line that has a line table entry of its own - we'll leave 437 // that source line to be printed when it actually occurs in the 438 // disassembly. 439 440 if (mixed_source_and_assembly && sc.line_entry.IsValid()) { 441 if (sc.symbol != previous_symbol) { 442 SourceLine decl_line = GetFunctionDeclLineEntry(sc); 443 if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line) == 444 false) 445 AddLineToSourceLineTables(decl_line, source_lines_seen); 446 } 447 if (sc.line_entry.IsValid()) { 448 SourceLine this_line; 449 this_line.file = sc.line_entry.file; 450 this_line.line = sc.line_entry.line; 451 if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line) == 452 false) 453 AddLineToSourceLineTables(this_line, source_lines_seen); 454 } 455 } 456 } 457 sc.Clear(false); 458 } 459 } 460 } 461 462 previous_symbol = nullptr; 463 SourceLine previous_line; 464 for (size_t i = 0; i < num_instructions_found; ++i) { 465 Instruction *inst = 466 disasm_ptr->GetInstructionList().GetInstructionAtIndex(i).get(); 467 468 if (inst) { 469 const Address &addr = inst->GetAddress(); 470 const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr; 471 SourceLinesToDisplay source_lines_to_display; 472 473 prev_sc = sc; 474 475 ModuleSP module_sp(addr.GetModule()); 476 if (module_sp) { 477 uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress( 478 addr, eSymbolContextEverything, sc); 479 if (resolved_mask) { 480 if (mixed_source_and_assembly) { 481 482 // If we've started a new function (non-inlined), print all of the 483 // source lines from the 484 // function declaration until the first line table entry - typically 485 // the opening curly brace of 486 // the function. 487 if (previous_symbol != sc.symbol) { 488 // The default disassembly format puts an extra blank line between 489 // functions - so 490 // when we're displaying the source context for a function, we 491 // don't want to add 492 // a blank line after the source context or we'll end up with two 493 // of them. 494 if (previous_symbol != nullptr) 495 source_lines_to_display.print_source_context_end_eol = false; 496 497 previous_symbol = sc.symbol; 498 if (sc.function && sc.line_entry.IsValid()) { 499 LineEntry prologue_end_line = sc.line_entry; 500 if (ElideMixedSourceAndDisassemblyLine( 501 exe_ctx, sc, prologue_end_line) == false) { 502 FileSpec func_decl_file; 503 uint32_t func_decl_line; 504 sc.function->GetStartLineSourceInfo(func_decl_file, 505 func_decl_line); 506 if (func_decl_file == prologue_end_line.file || 507 func_decl_file == prologue_end_line.original_file) { 508 // Add all the lines between the function declaration 509 // and the first non-prologue source line to the list 510 // of lines to print. 511 for (uint32_t lineno = func_decl_line; 512 lineno <= prologue_end_line.line; lineno++) { 513 SourceLine this_line; 514 this_line.file = func_decl_file; 515 this_line.line = lineno; 516 source_lines_to_display.lines.push_back(this_line); 517 } 518 // Mark the last line as the "current" one. Usually 519 // this is the open curly brace. 520 if (source_lines_to_display.lines.size() > 0) 521 source_lines_to_display.current_source_line = 522 source_lines_to_display.lines.size() - 1; 523 } 524 } 525 } 526 sc.GetAddressRange(scope, 0, use_inline_block_range, 527 current_source_line_range); 528 } 529 530 // If we've left a previous source line's address range, print a new 531 // source line 532 if (!current_source_line_range.ContainsFileAddress(addr)) { 533 sc.GetAddressRange(scope, 0, use_inline_block_range, 534 current_source_line_range); 535 536 if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) { 537 SourceLine this_line; 538 this_line.file = sc.line_entry.file; 539 this_line.line = sc.line_entry.line; 540 541 if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, 542 this_line) == false) { 543 // Only print this source line if it is different from the 544 // last source line we printed. There may have been inlined 545 // functions between these lines that we elided, resulting in 546 // the same line being printed twice in a row for a contiguous 547 // block of assembly instructions. 548 if (this_line != previous_line) { 549 550 std::vector<uint32_t> previous_lines; 551 for (uint32_t i = 0; 552 i < num_mixed_context_lines && 553 (this_line.line - num_mixed_context_lines) > 0; 554 i++) { 555 uint32_t line = 556 this_line.line - num_mixed_context_lines + i; 557 auto pos = source_lines_seen.find(this_line.file); 558 if (pos != source_lines_seen.end()) { 559 if (pos->second.count(line) == 1) { 560 previous_lines.clear(); 561 } else { 562 previous_lines.push_back(line); 563 } 564 } 565 } 566 for (size_t i = 0; i < previous_lines.size(); i++) { 567 SourceLine previous_line; 568 previous_line.file = this_line.file; 569 previous_line.line = previous_lines[i]; 570 auto pos = source_lines_seen.find(previous_line.file); 571 if (pos != source_lines_seen.end()) { 572 pos->second.insert(previous_line.line); 573 } 574 source_lines_to_display.lines.push_back(previous_line); 575 } 576 577 source_lines_to_display.lines.push_back(this_line); 578 source_lines_to_display.current_source_line = 579 source_lines_to_display.lines.size() - 1; 580 581 for (uint32_t i = 0; i < num_mixed_context_lines; i++) { 582 SourceLine next_line; 583 next_line.file = this_line.file; 584 next_line.line = this_line.line + i + 1; 585 auto pos = source_lines_seen.find(next_line.file); 586 if (pos != source_lines_seen.end()) { 587 if (pos->second.count(next_line.line) == 1) 588 break; 589 pos->second.insert(next_line.line); 590 } 591 source_lines_to_display.lines.push_back(next_line); 592 } 593 } 594 previous_line = this_line; 595 } 596 } 597 } 598 } 599 } else { 600 sc.Clear(true); 601 } 602 } 603 604 if (source_lines_to_display.lines.size() > 0) { 605 strm.EOL(); 606 for (size_t idx = 0; idx < source_lines_to_display.lines.size(); 607 idx++) { 608 SourceLine ln = source_lines_to_display.lines[idx]; 609 const char *line_highlight = ""; 610 if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) { 611 line_highlight = "->"; 612 } else if (idx == source_lines_to_display.current_source_line) { 613 line_highlight = "**"; 614 } 615 source_manager.DisplaySourceLinesWithLineNumbers( 616 ln.file, ln.line, 0, 0, line_highlight, &strm); 617 } 618 if (source_lines_to_display.print_source_context_end_eol) 619 strm.EOL(); 620 } 621 622 const bool show_bytes = (options & eOptionShowBytes) != 0; 623 inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, 624 &prev_sc, nullptr, address_text_size); 625 strm.EOL(); 626 } else { 627 break; 628 } 629 } 630 631 return true; 632 } 633 634 bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, 635 const char *plugin_name, const char *flavor, 636 const ExecutionContext &exe_ctx, 637 uint32_t num_instructions, 638 bool mixed_source_and_assembly, 639 uint32_t num_mixed_context_lines, 640 uint32_t options, Stream &strm) { 641 AddressRange range; 642 StackFrame *frame = exe_ctx.GetFramePtr(); 643 if (frame) { 644 SymbolContext sc( 645 frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); 646 if (sc.function) { 647 range = sc.function->GetAddressRange(); 648 } else if (sc.symbol && sc.symbol->ValueIsAddress()) { 649 range.GetBaseAddress() = sc.symbol->GetAddressRef(); 650 range.SetByteSize(sc.symbol->GetByteSize()); 651 } else { 652 range.GetBaseAddress() = frame->GetFrameCodeAddress(); 653 } 654 655 if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0) 656 range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); 657 } 658 659 return Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, range, 660 num_instructions, mixed_source_and_assembly, 661 num_mixed_context_lines, options, strm); 662 } 663 664 Instruction::Instruction(const Address &address, AddressClass addr_class) 665 : m_address(address), m_address_class(addr_class), m_opcode(), 666 m_calculated_strings(false) {} 667 668 Instruction::~Instruction() = default; 669 670 AddressClass Instruction::GetAddressClass() { 671 if (m_address_class == eAddressClassInvalid) 672 m_address_class = m_address.GetAddressClass(); 673 return m_address_class; 674 } 675 676 void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, 677 bool show_address, bool show_bytes, 678 const ExecutionContext *exe_ctx, 679 const SymbolContext *sym_ctx, 680 const SymbolContext *prev_sym_ctx, 681 const FormatEntity::Entry *disassembly_addr_format, 682 size_t max_address_text_size) { 683 size_t opcode_column_width = 7; 684 const size_t operand_column_width = 25; 685 686 CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx); 687 688 StreamString ss; 689 690 if (show_address) { 691 Debugger::FormatDisassemblerAddress(disassembly_addr_format, sym_ctx, 692 prev_sym_ctx, exe_ctx, &m_address, ss); 693 ss.FillLastLineToColumn(max_address_text_size, ' '); 694 } 695 696 if (show_bytes) { 697 if (m_opcode.GetType() == Opcode::eTypeBytes) { 698 // x86_64 and i386 are the only ones that use bytes right now so 699 // pad out the byte dump to be able to always show 15 bytes (3 chars each) 700 // plus a space 701 if (max_opcode_byte_size > 0) 702 m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1); 703 else 704 m_opcode.Dump(&ss, 15 * 3 + 1); 705 } else { 706 // Else, we have ARM or MIPS which can show up to a uint32_t 707 // 0x00000000 (10 spaces) plus two for padding... 708 if (max_opcode_byte_size > 0) 709 m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1); 710 else 711 m_opcode.Dump(&ss, 12); 712 } 713 } 714 715 const size_t opcode_pos = ss.GetSizeOfLastLine(); 716 717 // The default opcode size of 7 characters is plenty for most architectures 718 // but some like arm can pull out the occasional vqrshrun.s16. We won't get 719 // consistent column spacing in these cases, unfortunately. 720 if (m_opcode_name.length() >= opcode_column_width) { 721 opcode_column_width = m_opcode_name.length() + 1; 722 } 723 724 ss.PutCString(m_opcode_name.c_str()); 725 ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' '); 726 ss.PutCString(m_mnemonics.c_str()); 727 728 if (!m_comment.empty()) { 729 ss.FillLastLineToColumn( 730 opcode_pos + opcode_column_width + operand_column_width, ' '); 731 ss.PutCString(" ; "); 732 ss.PutCString(m_comment.c_str()); 733 } 734 s->Write(ss.GetData(), ss.GetSize()); 735 } 736 737 bool Instruction::DumpEmulation(const ArchSpec &arch) { 738 std::unique_ptr<EmulateInstruction> insn_emulator_ap( 739 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr)); 740 if (insn_emulator_ap) { 741 insn_emulator_ap->SetInstruction(GetOpcode(), GetAddress(), nullptr); 742 return insn_emulator_ap->EvaluateInstruction(0); 743 } 744 745 return false; 746 } 747 748 bool Instruction::HasDelaySlot() { 749 // Default is false. 750 return false; 751 } 752 753 OptionValueSP Instruction::ReadArray(FILE *in_file, Stream *out_stream, 754 OptionValue::Type data_type) { 755 bool done = false; 756 char buffer[1024]; 757 758 OptionValueSP option_value_sp(new OptionValueArray(1u << data_type)); 759 760 int idx = 0; 761 while (!done) { 762 if (!fgets(buffer, 1023, in_file)) { 763 out_stream->Printf( 764 "Instruction::ReadArray: Error reading file (fgets).\n"); 765 option_value_sp.reset(); 766 return option_value_sp; 767 } 768 769 std::string line(buffer); 770 771 size_t len = line.size(); 772 if (line[len - 1] == '\n') { 773 line[len - 1] = '\0'; 774 line.resize(len - 1); 775 } 776 777 if ((line.size() == 1) && line[0] == ']') { 778 done = true; 779 line.clear(); 780 } 781 782 if (!line.empty()) { 783 std::string value; 784 static RegularExpression g_reg_exp("^[ \t]*([^ \t]+)[ \t]*$"); 785 RegularExpression::Match regex_match(1); 786 bool reg_exp_success = g_reg_exp.Execute(line.c_str(), ®ex_match); 787 if (reg_exp_success) 788 regex_match.GetMatchAtIndex(line.c_str(), 1, value); 789 else 790 value = line; 791 792 OptionValueSP data_value_sp; 793 switch (data_type) { 794 case OptionValue::eTypeUInt64: 795 data_value_sp.reset(new OptionValueUInt64(0, 0)); 796 data_value_sp->SetValueFromString(value); 797 break; 798 // Other types can be added later as needed. 799 default: 800 data_value_sp.reset(new OptionValueString(value.c_str(), "")); 801 break; 802 } 803 804 option_value_sp->GetAsArray()->InsertValue(idx, data_value_sp); 805 ++idx; 806 } 807 } 808 809 return option_value_sp; 810 } 811 812 OptionValueSP Instruction::ReadDictionary(FILE *in_file, Stream *out_stream) { 813 bool done = false; 814 char buffer[1024]; 815 816 OptionValueSP option_value_sp(new OptionValueDictionary()); 817 static ConstString encoding_key("data_encoding"); 818 OptionValue::Type data_type = OptionValue::eTypeInvalid; 819 820 while (!done) { 821 // Read the next line in the file 822 if (!fgets(buffer, 1023, in_file)) { 823 out_stream->Printf( 824 "Instruction::ReadDictionary: Error reading file (fgets).\n"); 825 option_value_sp.reset(); 826 return option_value_sp; 827 } 828 829 // Check to see if the line contains the end-of-dictionary marker ("}") 830 std::string line(buffer); 831 832 size_t len = line.size(); 833 if (line[len - 1] == '\n') { 834 line[len - 1] = '\0'; 835 line.resize(len - 1); 836 } 837 838 if ((line.size() == 1) && (line[0] == '}')) { 839 done = true; 840 line.clear(); 841 } 842 843 // Try to find a key-value pair in the current line and add it to the 844 // dictionary. 845 if (!line.empty()) { 846 static RegularExpression g_reg_exp( 847 "^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$"); 848 RegularExpression::Match regex_match(2); 849 850 bool reg_exp_success = g_reg_exp.Execute(line.c_str(), ®ex_match); 851 std::string key; 852 std::string value; 853 if (reg_exp_success) { 854 regex_match.GetMatchAtIndex(line.c_str(), 1, key); 855 regex_match.GetMatchAtIndex(line.c_str(), 2, value); 856 } else { 857 out_stream->Printf("Instruction::ReadDictionary: Failure executing " 858 "regular expression.\n"); 859 option_value_sp.reset(); 860 return option_value_sp; 861 } 862 863 ConstString const_key(key.c_str()); 864 // Check value to see if it's the start of an array or dictionary. 865 866 lldb::OptionValueSP value_sp; 867 assert(value.empty() == false); 868 assert(key.empty() == false); 869 870 if (value[0] == '{') { 871 assert(value.size() == 1); 872 // value is a dictionary 873 value_sp = ReadDictionary(in_file, out_stream); 874 if (!value_sp) { 875 option_value_sp.reset(); 876 return option_value_sp; 877 } 878 } else if (value[0] == '[') { 879 assert(value.size() == 1); 880 // value is an array 881 value_sp = ReadArray(in_file, out_stream, data_type); 882 if (!value_sp) { 883 option_value_sp.reset(); 884 return option_value_sp; 885 } 886 // We've used the data_type to read an array; re-set the type to Invalid 887 data_type = OptionValue::eTypeInvalid; 888 } else if ((value[0] == '0') && (value[1] == 'x')) { 889 value_sp.reset(new OptionValueUInt64(0, 0)); 890 value_sp->SetValueFromString(value); 891 } else { 892 size_t len = value.size(); 893 if ((value[0] == '"') && (value[len - 1] == '"')) 894 value = value.substr(1, len - 2); 895 value_sp.reset(new OptionValueString(value.c_str(), "")); 896 } 897 898 if (const_key == encoding_key) { 899 // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data 900 // indicating the 901 // data type of an upcoming array (usually the next bit of data to be 902 // read in). 903 if (strcmp(value.c_str(), "uint32_t") == 0) 904 data_type = OptionValue::eTypeUInt64; 905 } else 906 option_value_sp->GetAsDictionary()->SetValueForKey(const_key, value_sp, 907 false); 908 } 909 } 910 911 return option_value_sp; 912 } 913 914 bool Instruction::TestEmulation(Stream *out_stream, const char *file_name) { 915 if (!out_stream) 916 return false; 917 918 if (!file_name) { 919 out_stream->Printf("Instruction::TestEmulation: Missing file_name."); 920 return false; 921 } 922 FILE *test_file = FileSystem::Fopen(file_name, "r"); 923 if (!test_file) { 924 out_stream->Printf( 925 "Instruction::TestEmulation: Attempt to open test file failed."); 926 return false; 927 } 928 929 char buffer[256]; 930 if (!fgets(buffer, 255, test_file)) { 931 out_stream->Printf( 932 "Instruction::TestEmulation: Error reading first line of test file.\n"); 933 fclose(test_file); 934 return false; 935 } 936 937 if (strncmp(buffer, "InstructionEmulationState={", 27) != 0) { 938 out_stream->Printf("Instructin::TestEmulation: Test file does not contain " 939 "emulation state dictionary\n"); 940 fclose(test_file); 941 return false; 942 } 943 944 // Read all the test information from the test file into an 945 // OptionValueDictionary. 946 947 OptionValueSP data_dictionary_sp(ReadDictionary(test_file, out_stream)); 948 if (!data_dictionary_sp) { 949 out_stream->Printf( 950 "Instruction::TestEmulation: Error reading Dictionary Object.\n"); 951 fclose(test_file); 952 return false; 953 } 954 955 fclose(test_file); 956 957 OptionValueDictionary *data_dictionary = 958 data_dictionary_sp->GetAsDictionary(); 959 static ConstString description_key("assembly_string"); 960 static ConstString triple_key("triple"); 961 962 OptionValueSP value_sp = data_dictionary->GetValueForKey(description_key); 963 964 if (!value_sp) { 965 out_stream->Printf("Instruction::TestEmulation: Test file does not " 966 "contain description string.\n"); 967 return false; 968 } 969 970 SetDescription(value_sp->GetStringValue()); 971 972 value_sp = data_dictionary->GetValueForKey(triple_key); 973 if (!value_sp) { 974 out_stream->Printf( 975 "Instruction::TestEmulation: Test file does not contain triple.\n"); 976 return false; 977 } 978 979 ArchSpec arch; 980 arch.SetTriple(llvm::Triple(value_sp->GetStringValue())); 981 982 bool success = false; 983 std::unique_ptr<EmulateInstruction> insn_emulator_ap( 984 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr)); 985 if (insn_emulator_ap) 986 success = 987 insn_emulator_ap->TestEmulation(out_stream, arch, data_dictionary); 988 989 if (success) 990 out_stream->Printf("Emulation test succeeded."); 991 else 992 out_stream->Printf("Emulation test failed."); 993 994 return success; 995 } 996 997 bool Instruction::Emulate( 998 const ArchSpec &arch, uint32_t evaluate_options, void *baton, 999 EmulateInstruction::ReadMemoryCallback read_mem_callback, 1000 EmulateInstruction::WriteMemoryCallback write_mem_callback, 1001 EmulateInstruction::ReadRegisterCallback read_reg_callback, 1002 EmulateInstruction::WriteRegisterCallback write_reg_callback) { 1003 std::unique_ptr<EmulateInstruction> insn_emulator_ap( 1004 EmulateInstruction::FindPlugin(arch, eInstructionTypeAny, nullptr)); 1005 if (insn_emulator_ap) { 1006 insn_emulator_ap->SetBaton(baton); 1007 insn_emulator_ap->SetCallbacks(read_mem_callback, write_mem_callback, 1008 read_reg_callback, write_reg_callback); 1009 insn_emulator_ap->SetInstruction(GetOpcode(), GetAddress(), nullptr); 1010 return insn_emulator_ap->EvaluateInstruction(evaluate_options); 1011 } 1012 1013 return false; 1014 } 1015 1016 uint32_t Instruction::GetData(DataExtractor &data) { 1017 return m_opcode.GetData(data); 1018 } 1019 1020 InstructionList::InstructionList() : m_instructions() {} 1021 1022 InstructionList::~InstructionList() = default; 1023 1024 size_t InstructionList::GetSize() const { return m_instructions.size(); } 1025 1026 uint32_t InstructionList::GetMaxOpcocdeByteSize() const { 1027 uint32_t max_inst_size = 0; 1028 collection::const_iterator pos, end; 1029 for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end; 1030 ++pos) { 1031 uint32_t inst_size = (*pos)->GetOpcode().GetByteSize(); 1032 if (max_inst_size < inst_size) 1033 max_inst_size = inst_size; 1034 } 1035 return max_inst_size; 1036 } 1037 1038 InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const { 1039 InstructionSP inst_sp; 1040 if (idx < m_instructions.size()) 1041 inst_sp = m_instructions[idx]; 1042 return inst_sp; 1043 } 1044 1045 void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes, 1046 const ExecutionContext *exe_ctx) { 1047 const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize(); 1048 collection::const_iterator pos, begin, end; 1049 1050 const FormatEntity::Entry *disassembly_format = nullptr; 1051 FormatEntity::Entry format; 1052 if (exe_ctx && exe_ctx->HasTargetScope()) { 1053 disassembly_format = 1054 exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); 1055 } else { 1056 FormatEntity::Parse("${addr}: ", format); 1057 disassembly_format = &format; 1058 } 1059 1060 for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin; 1061 pos != end; ++pos) { 1062 if (pos != begin) 1063 s->EOL(); 1064 (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, 1065 nullptr, nullptr, disassembly_format, 0); 1066 } 1067 } 1068 1069 void InstructionList::Clear() { m_instructions.clear(); } 1070 1071 void InstructionList::Append(lldb::InstructionSP &inst_sp) { 1072 if (inst_sp) 1073 m_instructions.push_back(inst_sp); 1074 } 1075 1076 uint32_t 1077 InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, 1078 Target &target) const { 1079 size_t num_instructions = m_instructions.size(); 1080 1081 uint32_t next_branch = UINT32_MAX; 1082 size_t i; 1083 for (i = start; i < num_instructions; i++) { 1084 if (m_instructions[i]->DoesBranch()) { 1085 next_branch = i; 1086 break; 1087 } 1088 } 1089 1090 // Hexagon needs the first instruction of the packet with the branch. 1091 // Go backwards until we find an instruction marked end-of-packet, or 1092 // until we hit start. 1093 if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon) { 1094 // If we didn't find a branch, find the last packet start. 1095 if (next_branch == UINT32_MAX) { 1096 i = num_instructions - 1; 1097 } 1098 1099 while (i > start) { 1100 --i; 1101 1102 Error error; 1103 uint32_t inst_bytes; 1104 bool prefer_file_cache = false; // Read from process if process is running 1105 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; 1106 target.ReadMemory(m_instructions[i]->GetAddress(), prefer_file_cache, 1107 &inst_bytes, sizeof(inst_bytes), error, &load_addr); 1108 // If we have an error reading memory, return start 1109 if (!error.Success()) 1110 return start; 1111 // check if this is the last instruction in a packet 1112 // bits 15:14 will be 11b or 00b for a duplex 1113 if (((inst_bytes & 0xC000) == 0xC000) || 1114 ((inst_bytes & 0xC000) == 0x0000)) { 1115 // instruction after this should be the start of next packet 1116 next_branch = i + 1; 1117 break; 1118 } 1119 } 1120 1121 if (next_branch == UINT32_MAX) { 1122 // We couldn't find the previous packet, so return start 1123 next_branch = start; 1124 } 1125 } 1126 return next_branch; 1127 } 1128 1129 uint32_t 1130 InstructionList::GetIndexOfInstructionAtAddress(const Address &address) { 1131 size_t num_instructions = m_instructions.size(); 1132 uint32_t index = UINT32_MAX; 1133 for (size_t i = 0; i < num_instructions; i++) { 1134 if (m_instructions[i]->GetAddress() == address) { 1135 index = i; 1136 break; 1137 } 1138 } 1139 return index; 1140 } 1141 1142 uint32_t 1143 InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr, 1144 Target &target) { 1145 Address address; 1146 address.SetLoadAddress(load_addr, &target); 1147 return GetIndexOfInstructionAtAddress(address); 1148 } 1149 1150 size_t Disassembler::ParseInstructions(const ExecutionContext *exe_ctx, 1151 const AddressRange &range, 1152 Stream *error_strm_ptr, 1153 bool prefer_file_cache) { 1154 if (exe_ctx) { 1155 Target *target = exe_ctx->GetTargetPtr(); 1156 const addr_t byte_size = range.GetByteSize(); 1157 if (target == nullptr || byte_size == 0 || 1158 !range.GetBaseAddress().IsValid()) 1159 return 0; 1160 1161 DataBufferHeap *heap_buffer = new DataBufferHeap(byte_size, '\0'); 1162 DataBufferSP data_sp(heap_buffer); 1163 1164 Error error; 1165 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; 1166 const size_t bytes_read = target->ReadMemory( 1167 range.GetBaseAddress(), prefer_file_cache, heap_buffer->GetBytes(), 1168 heap_buffer->GetByteSize(), error, &load_addr); 1169 1170 if (bytes_read > 0) { 1171 if (bytes_read != heap_buffer->GetByteSize()) 1172 heap_buffer->SetByteSize(bytes_read); 1173 DataExtractor data(data_sp, m_arch.GetByteOrder(), 1174 m_arch.GetAddressByteSize()); 1175 const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; 1176 return DecodeInstructions(range.GetBaseAddress(), data, 0, UINT32_MAX, 1177 false, data_from_file); 1178 } else if (error_strm_ptr) { 1179 const char *error_cstr = error.AsCString(); 1180 if (error_cstr) { 1181 error_strm_ptr->Printf("error: %s\n", error_cstr); 1182 } 1183 } 1184 } else if (error_strm_ptr) { 1185 error_strm_ptr->PutCString("error: invalid execution context\n"); 1186 } 1187 return 0; 1188 } 1189 1190 size_t Disassembler::ParseInstructions(const ExecutionContext *exe_ctx, 1191 const Address &start, 1192 uint32_t num_instructions, 1193 bool prefer_file_cache) { 1194 m_instruction_list.Clear(); 1195 1196 if (exe_ctx == nullptr || num_instructions == 0 || !start.IsValid()) 1197 return 0; 1198 1199 Target *target = exe_ctx->GetTargetPtr(); 1200 // Calculate the max buffer size we will need in order to disassemble 1201 const addr_t byte_size = num_instructions * m_arch.GetMaximumOpcodeByteSize(); 1202 1203 if (target == nullptr || byte_size == 0) 1204 return 0; 1205 1206 DataBufferHeap *heap_buffer = new DataBufferHeap(byte_size, '\0'); 1207 DataBufferSP data_sp(heap_buffer); 1208 1209 Error error; 1210 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; 1211 const size_t bytes_read = 1212 target->ReadMemory(start, prefer_file_cache, heap_buffer->GetBytes(), 1213 byte_size, error, &load_addr); 1214 1215 const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; 1216 1217 if (bytes_read == 0) 1218 return 0; 1219 DataExtractor data(data_sp, m_arch.GetByteOrder(), 1220 m_arch.GetAddressByteSize()); 1221 1222 const bool append_instructions = true; 1223 DecodeInstructions(start, data, 0, num_instructions, append_instructions, 1224 data_from_file); 1225 1226 return m_instruction_list.GetSize(); 1227 } 1228 1229 //---------------------------------------------------------------------- 1230 // Disassembler copy constructor 1231 //---------------------------------------------------------------------- 1232 Disassembler::Disassembler(const ArchSpec &arch, const char *flavor) 1233 : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS), 1234 m_flavor() { 1235 if (flavor == nullptr) 1236 m_flavor.assign("default"); 1237 else 1238 m_flavor.assign(flavor); 1239 1240 // If this is an arm variant that can only include thumb (T16, T32) 1241 // instructions, force the arch triple to be "thumbv.." instead of 1242 // "armv..." 1243 if (arch.IsAlwaysThumbInstructions()) { 1244 std::string thumb_arch_name(arch.GetTriple().getArchName().str()); 1245 // Replace "arm" with "thumb" so we get all thumb variants correct 1246 if (thumb_arch_name.size() > 3) { 1247 thumb_arch_name.erase(0, 3); 1248 thumb_arch_name.insert(0, "thumb"); 1249 } 1250 m_arch.SetTriple(thumb_arch_name.c_str()); 1251 } 1252 } 1253 1254 Disassembler::~Disassembler() = default; 1255 1256 InstructionList &Disassembler::GetInstructionList() { 1257 return m_instruction_list; 1258 } 1259 1260 const InstructionList &Disassembler::GetInstructionList() const { 1261 return m_instruction_list; 1262 } 1263 1264 //---------------------------------------------------------------------- 1265 // Class PseudoInstruction 1266 //---------------------------------------------------------------------- 1267 1268 PseudoInstruction::PseudoInstruction() 1269 : Instruction(Address(), eAddressClassUnknown), m_description() {} 1270 1271 PseudoInstruction::~PseudoInstruction() = default; 1272 1273 bool PseudoInstruction::DoesBranch() { 1274 // This is NOT a valid question for a pseudo instruction. 1275 return false; 1276 } 1277 1278 bool PseudoInstruction::HasDelaySlot() { 1279 // This is NOT a valid question for a pseudo instruction. 1280 return false; 1281 } 1282 1283 size_t PseudoInstruction::Decode(const lldb_private::Disassembler &disassembler, 1284 const lldb_private::DataExtractor &data, 1285 lldb::offset_t data_offset) { 1286 return m_opcode.GetByteSize(); 1287 } 1288 1289 void PseudoInstruction::SetOpcode(size_t opcode_size, void *opcode_data) { 1290 if (!opcode_data) 1291 return; 1292 1293 switch (opcode_size) { 1294 case 8: { 1295 uint8_t value8 = *((uint8_t *)opcode_data); 1296 m_opcode.SetOpcode8(value8, eByteOrderInvalid); 1297 break; 1298 } 1299 case 16: { 1300 uint16_t value16 = *((uint16_t *)opcode_data); 1301 m_opcode.SetOpcode16(value16, eByteOrderInvalid); 1302 break; 1303 } 1304 case 32: { 1305 uint32_t value32 = *((uint32_t *)opcode_data); 1306 m_opcode.SetOpcode32(value32, eByteOrderInvalid); 1307 break; 1308 } 1309 case 64: { 1310 uint64_t value64 = *((uint64_t *)opcode_data); 1311 m_opcode.SetOpcode64(value64, eByteOrderInvalid); 1312 break; 1313 } 1314 default: 1315 break; 1316 } 1317 } 1318 1319 void PseudoInstruction::SetDescription(const char *description) { 1320 if (description && strlen(description) > 0) 1321 m_description = description; 1322 } 1323