Files
clang-p2996/lldb/source/Commands/CommandObjectDisassemble.cpp
Greg Clayton 0c5cd90d63 Added function name types to allow us to set breakpoints by name more
intelligently. The four name types we currently have are:

eFunctionNameTypeFull       = (1 << 1), // The function name.
                                        // For C this is the same as just the name of the function
                                        // For C++ this is the demangled version of the mangled name.
                                        // For ObjC this is the full function signature with the + or
                                        // - and the square brackets and the class and selector
eFunctionNameTypeBase       = (1 << 2), // The function name only, no namespaces or arguments and no class 
                                        // methods or selectors will be searched.
eFunctionNameTypeMethod     = (1 << 3), // Find function by method name (C++) with no namespace or arguments
eFunctionNameTypeSelector   = (1 << 4)  // Find function by selector name (ObjC) names


this allows much more flexibility when setting breakoints:

(lldb) breakpoint set --name main --basename
(lldb) breakpoint set --name main --fullname
(lldb) breakpoint set --name main --method
(lldb) breakpoint set --name main --selector

The default:

(lldb) breakpoint set --name main

will inspect the name "main" and look for any parens, or if the name starts
with "-[" or "+[" and if any are found then a full name search will happen.
Else a basename search will be the default.

Fixed some command option structures so not all options are required when they
shouldn't be.

Cleaned up the breakpoint output summary.

Made the "image lookup --address <addr>" output much more verbose so it shows
all the important symbol context results. Added a GetDescription method to 
many of the SymbolContext objects for the more verbose output.

llvm-svn: 107075
2010-06-28 21:30:43 +00:00

416 lines
14 KiB
C++

//===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "CommandObjectDisassemble.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/AddressRange.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#define DEFAULT_DISASM_BYTE_SIZE 32
using namespace lldb;
using namespace lldb_private;
CommandObjectDisassemble::CommandOptions::CommandOptions () :
Options(),
m_func_name(),
m_start_addr(),
m_end_addr ()
{
ResetOptionValues();
}
CommandObjectDisassemble::CommandOptions::~CommandOptions ()
{
}
Error
CommandObjectDisassemble::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
{
Error error;
char short_option = (char) m_getopt_table[option_idx].val;
switch (short_option)
{
case 'm':
show_mixed = true;
break;
case 'c':
num_lines_context = Args::StringToUInt32(option_arg, 0, 0);
break;
case 'b':
show_bytes = true;
break;
case 's':
m_start_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
if (m_start_addr == LLDB_INVALID_ADDRESS)
m_start_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
if (m_start_addr == LLDB_INVALID_ADDRESS)
error.SetErrorStringWithFormat ("Invalid start address string '%s'.\n", optarg);
break;
case 'e':
m_end_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
if (m_end_addr == LLDB_INVALID_ADDRESS)
m_end_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
if (m_end_addr == LLDB_INVALID_ADDRESS)
error.SetErrorStringWithFormat ("Invalid end address string '%s'.\n", optarg);
break;
case 'n':
m_func_name = option_arg;
break;
case 'r':
raw = true;
break;
default:
error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
break;
}
return error;
}
void
CommandObjectDisassemble::CommandOptions::ResetOptionValues ()
{
Options::ResetOptionValues();
show_mixed = false;
show_bytes = false;
num_lines_context = 0;
m_func_name.clear();
m_start_addr = LLDB_INVALID_ADDRESS;
m_end_addr = LLDB_INVALID_ADDRESS;
raw = false;
}
const lldb::OptionDefinition*
CommandObjectDisassemble::CommandOptions::GetDefinitions ()
{
return g_option_table;
}
lldb::OptionDefinition
CommandObjectDisassemble::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."},
{ LLDB_OPT_SET_ALL, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."},
{ LLDB_OPT_SET_ALL, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."},
{ LLDB_OPT_SET_ALL, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."},
{ LLDB_OPT_SET_1, true, "start-address", 's', required_argument, NULL, 0, "<start-address>", "Address to start disassembling."},
{ LLDB_OPT_SET_1, false, "end-address", 'e', required_argument, NULL, 0, "<end-address>", "Address to start disassembling."},
{ LLDB_OPT_SET_2, true, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>", "Disassemble entire contents of the given function name."},
{ LLDB_OPT_SET_3, false, "current-frame", 'f', no_argument, NULL, 0, "<current-frame>", "Disassemble entire contents of the current frame's function."},
{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
};
//-------------------------------------------------------------------------
// CommandObjectDisassemble
//-------------------------------------------------------------------------
CommandObjectDisassemble::CommandObjectDisassemble () :
CommandObject ("disassemble",
"Disassemble bytes in the current function or anywhere in the inferior program.",
"disassemble [<cmd-options>]")
{
}
CommandObjectDisassemble::~CommandObjectDisassemble()
{
}
void
CommandObjectDisassemble::Disassemble
(
CommandInterpreter &interpreter,
CommandReturnObject &result,
Disassembler *disassembler,
const SymbolContextList &sc_list
)
{
const size_t count = sc_list.GetSize();
SymbolContext sc;
AddressRange range;
for (size_t i=0; i<count; ++i)
{
if (sc_list.GetContextAtIndex(i, sc) == false)
break;
if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range))
{
lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(interpreter.GetDebugger().GetExecutionContext().process);
if (addr != LLDB_INVALID_ADDRESS)
{
lldb::addr_t end_addr = addr + range.GetByteSize();
Disassemble (interpreter, result, disassembler, addr, end_addr);
}
}
}
}
void
CommandObjectDisassemble::Disassemble
(
CommandInterpreter &interpreter,
CommandReturnObject &result,
Disassembler *disassembler,
lldb::addr_t addr,
lldb::addr_t end_addr
)
{
if (addr == LLDB_INVALID_ADDRESS)
return;
if (end_addr == LLDB_INVALID_ADDRESS || addr >= end_addr)
end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
ExecutionContext exe_ctx (interpreter.GetDebugger().GetExecutionContext());
DataExtractor data;
size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, end_addr - addr, data);
if (bytes_disassembled == 0)
{
// Nothing got disassembled...
}
else
{
// We got some things disassembled...
size_t num_instructions = disassembler->GetInstructionList().GetSize();
uint32_t offset = 0;
Stream &output_stream = result.GetOutputStream();
SymbolContext sc;
SymbolContext prev_sc;
AddressRange sc_range;
if (m_options.show_mixed)
output_stream.IndentMore ();
for (size_t i=0; i<num_instructions; ++i)
{
Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
if (inst)
{
lldb::addr_t curr_addr = addr + offset;
if (m_options.show_mixed)
{
Process *process = interpreter.GetDebugger().GetExecutionContext().process;
if (!sc_range.ContainsLoadAddress (curr_addr, process))
{
prev_sc = sc;
Address curr_so_addr;
if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
{
if (curr_so_addr.GetSection())
{
Module *module = curr_so_addr.GetSection()->GetModule();
uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
if (resolved_mask)
{
sc.GetAddressRange (eSymbolContextEverything, sc_range);
if (sc != prev_sc)
{
if (offset != 0)
output_stream.EOL();
sc.DumpStopContext(&output_stream, process, curr_so_addr);
output_stream.EOL();
if (sc.comp_unit && sc.line_entry.IsValid())
{
interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbers (
sc.line_entry.file,
sc.line_entry.line,
m_options.num_lines_context,
m_options.num_lines_context,
m_options.num_lines_context ? "->" : "",
&output_stream);
}
}
}
}
}
}
}
if (m_options.show_mixed)
output_stream.IndentMore ();
output_stream.Indent();
size_t inst_byte_size = inst->GetByteSize();
inst->Dump(&output_stream, curr_addr, m_options.show_bytes ? &data : NULL, offset, exe_ctx, m_options.raw);
output_stream.EOL();
offset += inst_byte_size;
if (m_options.show_mixed)
output_stream.IndentLess ();
}
else
{
break;
}
}
if (m_options.show_mixed)
output_stream.IndentLess ();
}
}
bool
CommandObjectDisassemble::Execute
(
CommandInterpreter &interpreter,
Args& command,
CommandReturnObject &result
)
{
Target *target = interpreter.GetDebugger().GetCurrentTarget().get();
if (target == NULL)
{
result.AppendError ("invalid target, set executable file using 'file' command");
result.SetStatus (eReturnStatusFailed);
return false;
}
ArchSpec arch(target->GetArchitecture());
if (!arch.IsValid())
{
result.AppendError ("target needs valid architecure in order to be able to disassemble");
result.SetStatus (eReturnStatusFailed);
return false;
}
Disassembler *disassembler = Disassembler::FindPlugin(arch);
if (disassembler == NULL)
{
result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString());
result.SetStatus (eReturnStatusFailed);
return false;
}
result.SetStatus (eReturnStatusSuccessFinishResult);
lldb::addr_t addr = LLDB_INVALID_ADDRESS;
lldb::addr_t end_addr = LLDB_INVALID_ADDRESS;
ConstString name;
const size_t argc = command.GetArgumentCount();
if (argc != 0)
{
result.AppendErrorWithFormat ("\"disassemble\" doesn't take any arguments.\n");
result.SetStatus (eReturnStatusFailed);
return false;
}
if (m_options.m_start_addr != LLDB_INVALID_ADDRESS)
{
addr = m_options.m_start_addr;
if (m_options.m_end_addr != LLDB_INVALID_ADDRESS)
{
end_addr = m_options.m_end_addr;
if (end_addr < addr)
{
result.AppendErrorWithFormat ("End address before start address.\n");
result.SetStatus (eReturnStatusFailed);
return false;
}
}
else
end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
}
else if (!m_options.m_func_name.empty())
{
ConstString tmpname(m_options.m_func_name.c_str());
name = tmpname;
}
else
{
ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());
if (exe_ctx.frame)
{
SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
if (sc.function)
{
addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
if (addr != LLDB_INVALID_ADDRESS)
end_addr = addr + sc.function->GetAddressRange().GetByteSize();
}
else if (sc.symbol && sc.symbol->GetAddressRangePtr())
{
addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
if (addr != LLDB_INVALID_ADDRESS)
{
end_addr = addr + sc.symbol->GetAddressRangePtr()->GetByteSize();
if (addr == end_addr)
end_addr += DEFAULT_DISASM_BYTE_SIZE;
}
}
else
{
addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
if (addr != LLDB_INVALID_ADDRESS)
end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
}
}
else
{
result.AppendError ("invalid frame");
result.SetStatus (eReturnStatusFailed);
return false;
}
}
if (!name.IsEmpty())
{
SymbolContextList sc_list;
if (target->GetImages().FindFunctions(name,
eFunctionNameTypeBase | eFunctionNameTypeFull | eFunctionNameTypeMethod | eFunctionNameTypeSelector,
sc_list))
{
Disassemble (interpreter, result, disassembler, sc_list);
}
else if (target->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list))
{
Disassemble (interpreter, result, disassembler, sc_list);
}
else
{
result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
result.SetStatus (eReturnStatusFailed);
return false;
}
}
else
{
Disassemble (interpreter, result, disassembler, addr, end_addr);
}
return result.Succeeded();
}