1 | //===-- CommandObjectDisassemble.cpp --------------------------------------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "CommandObjectDisassemble.h" |
10 | #include "lldb/Core/AddressRange.h" |
11 | #include "lldb/Core/Disassembler.h" |
12 | #include "lldb/Core/Module.h" |
13 | #include "lldb/Host/OptionParser.h" |
14 | #include "lldb/Interpreter/CommandInterpreter.h" |
15 | #include "lldb/Interpreter/CommandOptionArgumentTable.h" |
16 | #include "lldb/Interpreter/CommandReturnObject.h" |
17 | #include "lldb/Interpreter/OptionArgParser.h" |
18 | #include "lldb/Interpreter/Options.h" |
19 | #include "lldb/Symbol/Function.h" |
20 | #include "lldb/Symbol/Symbol.h" |
21 | #include "lldb/Target/SectionLoadList.h" |
22 | #include "lldb/Target/StackFrame.h" |
23 | #include "lldb/Target/Target.h" |
24 | #include <iterator> |
25 | |
26 | static constexpr unsigned default_disasm_byte_size = 32; |
27 | static constexpr unsigned default_disasm_num_ins = 4; |
28 | |
29 | using namespace lldb; |
30 | using namespace lldb_private; |
31 | |
32 | #define LLDB_OPTIONS_disassemble |
33 | #include "CommandOptions.inc" |
34 | |
35 | CommandObjectDisassemble::CommandOptions::CommandOptions() { |
36 | OptionParsingStarting(execution_context: nullptr); |
37 | } |
38 | |
39 | CommandObjectDisassemble::CommandOptions::~CommandOptions() = default; |
40 | |
41 | Status CommandObjectDisassemble::CommandOptions::SetOptionValue( |
42 | uint32_t option_idx, llvm::StringRef option_arg, |
43 | ExecutionContext *execution_context) { |
44 | Status error; |
45 | |
46 | const int short_option = m_getopt_table[option_idx].val; |
47 | |
48 | switch (short_option) { |
49 | case 'm': |
50 | show_mixed = true; |
51 | break; |
52 | |
53 | case 'C': |
54 | if (option_arg.getAsInteger(Radix: 0, Result&: num_lines_context)) |
55 | error = Status::FromErrorStringWithFormat( |
56 | format: "invalid num context lines string: \"%s\"", option_arg.str().c_str()); |
57 | break; |
58 | |
59 | case 'c': |
60 | if (option_arg.getAsInteger(Radix: 0, Result&: num_instructions)) |
61 | error = Status::FromErrorStringWithFormat( |
62 | format: "invalid num of instructions string: \"%s\"", |
63 | option_arg.str().c_str()); |
64 | break; |
65 | |
66 | case 'b': |
67 | show_bytes = true; |
68 | break; |
69 | |
70 | case 'k': |
71 | show_control_flow_kind = true; |
72 | break; |
73 | |
74 | case 's': { |
75 | start_addr = OptionArgParser::ToAddress(exe_ctx: execution_context, s: option_arg, |
76 | LLDB_INVALID_ADDRESS, error_ptr: &error); |
77 | if (start_addr != LLDB_INVALID_ADDRESS) |
78 | some_location_specified = true; |
79 | } break; |
80 | case 'e': { |
81 | end_addr = OptionArgParser::ToAddress(exe_ctx: execution_context, s: option_arg, |
82 | LLDB_INVALID_ADDRESS, error_ptr: &error); |
83 | if (end_addr != LLDB_INVALID_ADDRESS) |
84 | some_location_specified = true; |
85 | } break; |
86 | |
87 | case 'n': |
88 | func_name.assign(str: std::string(option_arg)); |
89 | some_location_specified = true; |
90 | break; |
91 | |
92 | case 'p': |
93 | at_pc = true; |
94 | some_location_specified = true; |
95 | break; |
96 | |
97 | case 'l': |
98 | frame_line = true; |
99 | // Disassemble the current source line kind of implies showing mixed source |
100 | // code context. |
101 | show_mixed = true; |
102 | some_location_specified = true; |
103 | break; |
104 | |
105 | case 'P': |
106 | plugin_name.assign(str: std::string(option_arg)); |
107 | break; |
108 | |
109 | case 'F': { |
110 | TargetSP target_sp = |
111 | execution_context ? execution_context->GetTargetSP() : TargetSP(); |
112 | if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() == |
113 | llvm::Triple::x86 || |
114 | target_sp->GetArchitecture().GetTriple().getArch() == |
115 | llvm::Triple::x86_64)) { |
116 | flavor_string.assign(str: std::string(option_arg)); |
117 | } else |
118 | error = Status::FromErrorStringWithFormat( |
119 | format: "Disassembler flavors are currently only " |
120 | "supported for x86 and x86_64 targets."); |
121 | break; |
122 | } |
123 | |
124 | case 'X': |
125 | cpu_string = std::string(option_arg); |
126 | break; |
127 | |
128 | case 'Y': |
129 | features_string = std::string(option_arg); |
130 | break; |
131 | |
132 | case 'r': |
133 | raw = true; |
134 | break; |
135 | |
136 | case 'f': |
137 | current_function = true; |
138 | some_location_specified = true; |
139 | break; |
140 | |
141 | case 'A': |
142 | if (execution_context) { |
143 | const auto &target_sp = execution_context->GetTargetSP(); |
144 | auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr; |
145 | arch = Platform::GetAugmentedArchSpec(platform: platform_ptr, triple: option_arg); |
146 | } |
147 | break; |
148 | |
149 | case 'a': { |
150 | symbol_containing_addr = OptionArgParser::ToAddress( |
151 | exe_ctx: execution_context, s: option_arg, LLDB_INVALID_ADDRESS, error_ptr: &error); |
152 | if (symbol_containing_addr != LLDB_INVALID_ADDRESS) { |
153 | some_location_specified = true; |
154 | } |
155 | } break; |
156 | |
157 | case '\x01': |
158 | force = true; |
159 | break; |
160 | |
161 | default: |
162 | llvm_unreachable("Unimplemented option"); |
163 | } |
164 | |
165 | return error; |
166 | } |
167 | |
168 | void CommandObjectDisassemble::CommandOptions::OptionParsingStarting( |
169 | ExecutionContext *execution_context) { |
170 | show_mixed = false; |
171 | show_bytes = false; |
172 | show_control_flow_kind = false; |
173 | num_lines_context = 0; |
174 | num_instructions = 0; |
175 | func_name.clear(); |
176 | current_function = false; |
177 | at_pc = false; |
178 | frame_line = false; |
179 | start_addr = LLDB_INVALID_ADDRESS; |
180 | end_addr = LLDB_INVALID_ADDRESS; |
181 | symbol_containing_addr = LLDB_INVALID_ADDRESS; |
182 | raw = false; |
183 | plugin_name.clear(); |
184 | |
185 | Target *target = |
186 | execution_context ? execution_context->GetTargetPtr() : nullptr; |
187 | |
188 | if (target) { |
189 | // This is a hack till we get the ability to specify features based on |
190 | // architecture. For now GetDisassemblyFlavor is really only valid for x86 |
191 | // (and for the llvm assembler plugin, but I'm papering over that since that |
192 | // is the only disassembler plugin we have... |
193 | if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 || |
194 | target->GetArchitecture().GetTriple().getArch() == |
195 | llvm::Triple::x86_64) { |
196 | flavor_string.assign(s: target->GetDisassemblyFlavor()); |
197 | } else { |
198 | flavor_string.assign(s: "default"); |
199 | } |
200 | if (const char *cpu = target->GetDisassemblyCPU()) |
201 | cpu_string.assign(s: cpu); |
202 | if (const char *features = target->GetDisassemblyFeatures()) |
203 | features_string.assign(s: features); |
204 | } else { |
205 | flavor_string.assign(s: "default"); |
206 | cpu_string.assign(s: "default"); |
207 | features_string.assign(s: "default"); |
208 | } |
209 | |
210 | arch.Clear(); |
211 | some_location_specified = false; |
212 | force = false; |
213 | } |
214 | |
215 | Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished( |
216 | ExecutionContext *execution_context) { |
217 | if (!some_location_specified) |
218 | current_function = true; |
219 | return Status(); |
220 | } |
221 | |
222 | llvm::ArrayRef<OptionDefinition> |
223 | CommandObjectDisassemble::CommandOptions::GetDefinitions() { |
224 | return llvm::ArrayRef(g_disassemble_options); |
225 | } |
226 | |
227 | // CommandObjectDisassemble |
228 | |
229 | CommandObjectDisassemble::CommandObjectDisassemble( |
230 | CommandInterpreter &interpreter) |
231 | : CommandObjectParsed( |
232 | interpreter, "disassemble", |
233 | "Disassemble specified instructions in the current target. " |
234 | "Defaults to the current function for the current thread and " |
235 | "stack frame.", |
236 | "disassemble [<cmd-options>]", eCommandRequiresTarget) {} |
237 | |
238 | CommandObjectDisassemble::~CommandObjectDisassemble() = default; |
239 | |
240 | llvm::Expected<std::vector<AddressRange>> |
241 | CommandObjectDisassemble::CheckRangeSize(std::vector<AddressRange> ranges, |
242 | llvm::StringRef what) { |
243 | addr_t total_range_size = 0; |
244 | for (const AddressRange &r : ranges) |
245 | total_range_size += r.GetByteSize(); |
246 | |
247 | if (m_options.num_instructions > 0 || m_options.force || |
248 | total_range_size < GetDebugger().GetStopDisassemblyMaxSize()) |
249 | return ranges; |
250 | |
251 | StreamString msg; |
252 | msg << "Not disassembling "<< what << " because it is very large "; |
253 | for (const AddressRange &r : ranges) |
254 | r.Dump(s: &msg, target: &GetTarget(), style: Address::DumpStyleLoadAddress, |
255 | fallback_style: Address::DumpStyleFileAddress); |
256 | msg << ". To disassemble specify an instruction count limit, start/stop " |
257 | "addresses or use the --force option."; |
258 | return llvm::createStringError(S: msg.GetString()); |
259 | } |
260 | |
261 | llvm::Expected<std::vector<AddressRange>> |
262 | CommandObjectDisassemble::GetContainingAddressRanges() { |
263 | std::vector<AddressRange> ranges; |
264 | const auto &get_ranges = [&](Address addr) { |
265 | ModuleSP module_sp(addr.GetModule()); |
266 | SymbolContext sc; |
267 | bool resolve_tail_call_address = true; |
268 | addr.GetModule()->ResolveSymbolContextForAddress( |
269 | so_addr: addr, resolve_scope: eSymbolContextEverything, sc, resolve_tail_call_address); |
270 | if (sc.function || sc.symbol) { |
271 | AddressRange range; |
272 | for (uint32_t idx = 0; |
273 | sc.GetAddressRange(scope: eSymbolContextFunction | eSymbolContextSymbol, |
274 | range_idx: idx, use_inline_block_range: false, range); |
275 | ++idx) |
276 | ranges.push_back(x: range); |
277 | } |
278 | }; |
279 | |
280 | Target &target = GetTarget(); |
281 | if (target.HasLoadedSections()) { |
282 | Address symbol_containing_address; |
283 | if (target.ResolveLoadAddress(load_addr: m_options.symbol_containing_addr, |
284 | so_addr&: symbol_containing_address)) { |
285 | get_ranges(symbol_containing_address); |
286 | } |
287 | } else { |
288 | for (lldb::ModuleSP module_sp : target.GetImages().Modules()) { |
289 | Address file_address; |
290 | if (module_sp->ResolveFileAddress(vm_addr: m_options.symbol_containing_addr, |
291 | so_addr&: file_address)) { |
292 | get_ranges(file_address); |
293 | } |
294 | } |
295 | } |
296 | |
297 | if (ranges.empty()) { |
298 | return llvm::createStringError( |
299 | EC: llvm::inconvertibleErrorCode(), |
300 | Fmt: "Could not find function bounds for address 0x%"PRIx64, |
301 | Vals: m_options.symbol_containing_addr); |
302 | } |
303 | |
304 | return CheckRangeSize(ranges: std::move(ranges), what: "the function"); |
305 | } |
306 | |
307 | llvm::Expected<std::vector<AddressRange>> |
308 | CommandObjectDisassemble::GetCurrentFunctionRanges() { |
309 | Process *process = m_exe_ctx.GetProcessPtr(); |
310 | StackFrame *frame = m_exe_ctx.GetFramePtr(); |
311 | if (!frame) { |
312 | if (process) { |
313 | return llvm::createStringError( |
314 | Fmt: "Cannot disassemble around the current function without the process " |
315 | "being stopped.\n"); |
316 | } |
317 | return llvm::createStringError( |
318 | Fmt: "Cannot disassemble around the current function without a selected " |
319 | "frame: no currently running process.\n"); |
320 | } |
321 | SymbolContext sc = |
322 | frame->GetSymbolContext(resolve_scope: eSymbolContextFunction | eSymbolContextSymbol); |
323 | std::vector<AddressRange> ranges; |
324 | if (sc.function) |
325 | ranges = sc.function->GetAddressRanges(); |
326 | else if (sc.symbol && sc.symbol->ValueIsAddress()) |
327 | ranges.emplace_back(args: sc.symbol->GetAddress(), args: sc.symbol->GetByteSize()); |
328 | else |
329 | ranges.emplace_back(args: frame->GetFrameCodeAddress(), args: default_disasm_byte_size); |
330 | |
331 | return CheckRangeSize(ranges: std::move(ranges), what: "the current function"); |
332 | } |
333 | |
334 | llvm::Expected<std::vector<AddressRange>> |
335 | CommandObjectDisassemble::GetCurrentLineRanges() { |
336 | Process *process = m_exe_ctx.GetProcessPtr(); |
337 | StackFrame *frame = m_exe_ctx.GetFramePtr(); |
338 | if (!frame) { |
339 | if (process) { |
340 | return llvm::createStringError( |
341 | EC: llvm::inconvertibleErrorCode(), |
342 | S: "Cannot disassemble around the current " |
343 | "function without the process being stopped.\n"); |
344 | } else { |
345 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
346 | S: "Cannot disassemble around the current " |
347 | "line without a selected frame: " |
348 | "no currently running process.\n"); |
349 | } |
350 | } |
351 | |
352 | LineEntry pc_line_entry( |
353 | frame->GetSymbolContext(resolve_scope: eSymbolContextLineEntry).line_entry); |
354 | if (pc_line_entry.IsValid()) |
355 | return std::vector<AddressRange>{pc_line_entry.range}; |
356 | |
357 | // No line entry, so just disassemble around the current pc |
358 | m_options.show_mixed = false; |
359 | return GetPCRanges(); |
360 | } |
361 | |
362 | llvm::Expected<std::vector<AddressRange>> |
363 | CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) { |
364 | ConstString name(m_options.func_name.c_str()); |
365 | |
366 | ModuleFunctionSearchOptions function_options; |
367 | function_options.include_symbols = true; |
368 | function_options.include_inlines = true; |
369 | |
370 | // Find functions matching the given name. |
371 | SymbolContextList sc_list; |
372 | GetTarget().GetImages().FindFunctions(name, name_type_mask: eFunctionNameTypeAuto, |
373 | options: function_options, sc_list); |
374 | |
375 | std::vector<AddressRange> ranges; |
376 | llvm::Error range_errs = llvm::Error::success(); |
377 | const uint32_t scope = |
378 | eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol; |
379 | const bool use_inline_block_range = true; |
380 | for (SymbolContext sc : sc_list.SymbolContexts()) { |
381 | std::vector<AddressRange> fn_ranges; |
382 | AddressRange range; |
383 | for (uint32_t range_idx = 0; |
384 | sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); |
385 | ++range_idx) |
386 | fn_ranges.push_back(x: std::move(range)); |
387 | |
388 | if (llvm::Expected<std::vector<AddressRange>> checked_ranges = |
389 | CheckRangeSize(ranges: std::move(fn_ranges), what: "a function")) |
390 | llvm::move(Range&: *checked_ranges, Out: std::back_inserter(x&: ranges)); |
391 | else |
392 | range_errs = |
393 | joinErrors(E1: std::move(range_errs), E2: checked_ranges.takeError()); |
394 | } |
395 | if (ranges.empty()) { |
396 | if (range_errs) |
397 | return std::move(range_errs); |
398 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
399 | Fmt: "Unable to find symbol with name '%s'.\n", |
400 | Vals: name.GetCString()); |
401 | } |
402 | if (range_errs) |
403 | result.AppendWarning(in_string: toString(E: std::move(range_errs))); |
404 | return ranges; |
405 | } |
406 | |
407 | llvm::Expected<std::vector<AddressRange>> |
408 | CommandObjectDisassemble::GetPCRanges() { |
409 | Process *process = m_exe_ctx.GetProcessPtr(); |
410 | StackFrame *frame = m_exe_ctx.GetFramePtr(); |
411 | if (!frame) { |
412 | if (process) { |
413 | return llvm::createStringError( |
414 | EC: llvm::inconvertibleErrorCode(), |
415 | S: "Cannot disassemble around the current " |
416 | "function without the process being stopped.\n"); |
417 | } else { |
418 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
419 | S: "Cannot disassemble around the current " |
420 | "PC without a selected frame: " |
421 | "no currently running process.\n"); |
422 | } |
423 | } |
424 | |
425 | if (m_options.num_instructions == 0) { |
426 | // Disassembling at the PC always disassembles some number of |
427 | // instructions (not the whole function). |
428 | m_options.num_instructions = default_disasm_num_ins; |
429 | } |
430 | return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}}; |
431 | } |
432 | |
433 | llvm::Expected<std::vector<AddressRange>> |
434 | CommandObjectDisassemble::GetStartEndAddressRanges() { |
435 | addr_t size = 0; |
436 | if (m_options.end_addr != LLDB_INVALID_ADDRESS) { |
437 | if (m_options.end_addr <= m_options.start_addr) { |
438 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
439 | S: "End address before start address."); |
440 | } |
441 | size = m_options.end_addr - m_options.start_addr; |
442 | } |
443 | return std::vector<AddressRange>{{Address(m_options.start_addr), size}}; |
444 | } |
445 | |
446 | llvm::Expected<std::vector<AddressRange>> |
447 | CommandObjectDisassemble::GetRangesForSelectedMode( |
448 | CommandReturnObject &result) { |
449 | if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) |
450 | return CommandObjectDisassemble::GetContainingAddressRanges(); |
451 | if (m_options.current_function) |
452 | return CommandObjectDisassemble::GetCurrentFunctionRanges(); |
453 | if (m_options.frame_line) |
454 | return CommandObjectDisassemble::GetCurrentLineRanges(); |
455 | if (!m_options.func_name.empty()) |
456 | return CommandObjectDisassemble::GetNameRanges(result); |
457 | if (m_options.start_addr != LLDB_INVALID_ADDRESS) |
458 | return CommandObjectDisassemble::GetStartEndAddressRanges(); |
459 | return CommandObjectDisassemble::GetPCRanges(); |
460 | } |
461 | |
462 | void CommandObjectDisassemble::DoExecute(Args &command, |
463 | CommandReturnObject &result) { |
464 | Target &target = GetTarget(); |
465 | |
466 | if (!m_options.arch.IsValid()) |
467 | m_options.arch = target.GetArchitecture(); |
468 | |
469 | if (!m_options.arch.IsValid()) { |
470 | result.AppendError( |
471 | in_string: "use the --arch option or set the target architecture to disassemble"); |
472 | return; |
473 | } |
474 | |
475 | const char *plugin_name = m_options.GetPluginName(); |
476 | const char *flavor_string = m_options.GetFlavorString(); |
477 | const char *cpu_string = m_options.GetCPUString(); |
478 | const char *features_string = m_options.GetFeaturesString(); |
479 | |
480 | DisassemblerSP disassembler = Disassembler::FindPlugin( |
481 | arch: m_options.arch, flavor: flavor_string, cpu: cpu_string, features: features_string, plugin_name); |
482 | |
483 | if (!disassembler) { |
484 | if (plugin_name) { |
485 | result.AppendErrorWithFormat( |
486 | format: "Unable to find Disassembler plug-in named '%s' that supports the " |
487 | "'%s' architecture.\n", |
488 | plugin_name, m_options.arch.GetArchitectureName()); |
489 | } else |
490 | result.AppendErrorWithFormat( |
491 | format: "Unable to find Disassembler plug-in for the '%s' architecture.\n", |
492 | m_options.arch.GetArchitectureName()); |
493 | return; |
494 | } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec( |
495 | arch: m_options.arch, flavor: flavor_string)) |
496 | result.AppendWarningWithFormat( |
497 | format: "invalid disassembler flavor \"%s\", using default.\n", flavor_string); |
498 | |
499 | result.SetStatus(eReturnStatusSuccessFinishResult); |
500 | |
501 | if (!command.empty()) { |
502 | result.AppendErrorWithFormat( |
503 | format: "\"disassemble\" arguments are specified as options.\n"); |
504 | const int terminal_width = |
505 | GetCommandInterpreter().GetDebugger().GetTerminalWidth(); |
506 | GetOptions()->GenerateOptionUsage(strm&: result.GetErrorStream(), cmd&: *this, |
507 | screen_width: terminal_width); |
508 | return; |
509 | } |
510 | |
511 | if (m_options.show_mixed && m_options.num_lines_context == 0) |
512 | m_options.num_lines_context = 2; |
513 | |
514 | // Always show the PC in the disassembly |
515 | uint32_t options = Disassembler::eOptionMarkPCAddress; |
516 | |
517 | // Mark the source line for the current PC only if we are doing mixed source |
518 | // and assembly |
519 | if (m_options.show_mixed) |
520 | options |= Disassembler::eOptionMarkPCSourceLine; |
521 | |
522 | if (m_options.show_bytes) |
523 | options |= Disassembler::eOptionShowBytes; |
524 | |
525 | if (m_options.show_control_flow_kind) |
526 | options |= Disassembler::eOptionShowControlFlowKind; |
527 | |
528 | if (m_options.raw) |
529 | options |= Disassembler::eOptionRawOuput; |
530 | |
531 | llvm::Expected<std::vector<AddressRange>> ranges = |
532 | GetRangesForSelectedMode(result); |
533 | if (!ranges) { |
534 | result.AppendError(in_string: toString(E: ranges.takeError())); |
535 | return; |
536 | } |
537 | |
538 | bool print_sc_header = ranges->size() > 1; |
539 | for (AddressRange cur_range : *ranges) { |
540 | Disassembler::Limit limit; |
541 | if (m_options.num_instructions == 0) { |
542 | limit = {.kind: Disassembler::Limit::Bytes, .value: cur_range.GetByteSize()}; |
543 | if (limit.value == 0) |
544 | limit.value = default_disasm_byte_size; |
545 | } else { |
546 | limit = {.kind: Disassembler::Limit::Instructions, .value: m_options.num_instructions}; |
547 | } |
548 | if (Disassembler::Disassemble( |
549 | debugger&: GetDebugger(), arch: m_options.arch, plugin_name, flavor: flavor_string, |
550 | cpu: cpu_string, features: features_string, exe_ctx: m_exe_ctx, start: cur_range.GetBaseAddress(), |
551 | limit, mixed_source_and_assembly: m_options.show_mixed, |
552 | num_mixed_context_lines: m_options.show_mixed ? m_options.num_lines_context : 0, options, |
553 | strm&: result.GetOutputStream())) { |
554 | result.SetStatus(eReturnStatusSuccessFinishResult); |
555 | } else { |
556 | if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) { |
557 | result.AppendErrorWithFormat( |
558 | format: "Failed to disassemble memory in function at 0x%8.8"PRIx64 ".\n", |
559 | m_options.symbol_containing_addr); |
560 | } else { |
561 | result.AppendErrorWithFormat( |
562 | format: "Failed to disassemble memory at 0x%8.8"PRIx64 ".\n", |
563 | cur_range.GetBaseAddress().GetLoadAddress(target: &target)); |
564 | } |
565 | } |
566 | if (print_sc_header) |
567 | result.GetOutputStream() << "\n"; |
568 | } |
569 | } |
570 |
Definitions
- default_disasm_byte_size
- default_disasm_num_ins
- CommandOptions
- ~CommandOptions
- SetOptionValue
- OptionParsingStarting
- OptionParsingFinished
- GetDefinitions
- CommandObjectDisassemble
- ~CommandObjectDisassemble
- CheckRangeSize
- GetContainingAddressRanges
- GetCurrentFunctionRanges
- GetCurrentLineRanges
- GetNameRanges
- GetPCRanges
- GetStartEndAddressRanges
- GetRangesForSelectedMode
Improve your Profiling and Debugging skills
Find out more