Added a thread plan tracer that prints lines of
assembly as well as registers that changed. llvm-svn: 118879
This commit is contained in:
parent
9aa60e964e
commit
8c9e538384
|
@ -15,6 +15,7 @@
|
|||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Symbol/TaggedASTType.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
@ -99,6 +100,24 @@ private:
|
|||
lldb::StreamSP m_stream_sp;
|
||||
};
|
||||
|
||||
class ThreadPlanAssemblyTracer : public ThreadPlanTracer
|
||||
{
|
||||
public:
|
||||
ThreadPlanAssemblyTracer (Thread &thread, lldb::StreamSP &stream_sp);
|
||||
virtual ~ThreadPlanAssemblyTracer ();
|
||||
virtual void TracingStarted ();
|
||||
virtual void TracingEnded ();
|
||||
virtual void Log();
|
||||
private:
|
||||
Process &m_process;
|
||||
Target &m_target;
|
||||
Disassembler *m_disassembler;
|
||||
const ABI *m_abi;
|
||||
TypeFromUser m_intptr_type;
|
||||
std::vector<uint64_t> m_register_values;
|
||||
lldb::DataBufferSP m_buffer_sp;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_ThreadPlanTracer_h_
|
||||
|
|
|
@ -10,12 +10,18 @@
|
|||
#include "lldb/Target/ThreadPlan.h"
|
||||
|
||||
// C Includes
|
||||
#include <string.h>
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include "lldb/Core/DataBufferHeap.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/Disassembler.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Core/Value.h"
|
||||
#include "lldb/Symbol/TypeList.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
|
@ -24,6 +30,8 @@
|
|||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
#pragma mark ThreadPlanTracer
|
||||
|
||||
ThreadPlanTracer::ThreadPlanTracer (Thread &thread, lldb::StreamSP &stream_sp) :
|
||||
m_single_step(true),
|
||||
m_enabled (false),
|
||||
|
@ -75,3 +83,200 @@ ThreadPlanTracer::TracerExplainsStop ()
|
|||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma mark ThreadPlanAssemblyTracer
|
||||
|
||||
ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread, lldb::StreamSP &stream_sp) :
|
||||
ThreadPlanTracer (thread, stream_sp),
|
||||
m_process(thread.GetProcess()),
|
||||
m_target(thread.GetProcess().GetTarget())
|
||||
{
|
||||
Process &process = thread.GetProcess();
|
||||
Target &target = process.GetTarget();
|
||||
|
||||
ArchSpec arch(target.GetArchitecture());
|
||||
|
||||
m_disassembler = Disassembler::FindPlugin(arch);
|
||||
|
||||
m_abi = process.GetABI();
|
||||
|
||||
ModuleSP executableModuleSP (target.GetExecutableModule());
|
||||
TypeList *type_list = executableModuleSP->GetTypeList();
|
||||
|
||||
if (type_list)
|
||||
{
|
||||
m_intptr_type = TypeFromUser(type_list->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, arch.GetAddressByteSize() * 8),
|
||||
type_list->GetClangASTContext().getASTContext());
|
||||
}
|
||||
|
||||
const unsigned int buf_size = 32;
|
||||
|
||||
m_buffer_sp.reset(new DataBufferHeap(buf_size, 0));
|
||||
}
|
||||
|
||||
ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer()
|
||||
{
|
||||
}
|
||||
|
||||
void ThreadPlanAssemblyTracer::TracingStarted ()
|
||||
{
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext();
|
||||
|
||||
if (m_register_values.size() == 0)
|
||||
{
|
||||
for (uint32_t reg_index = 0, num_registers = reg_ctx->GetRegisterCount();
|
||||
reg_index < num_registers;
|
||||
++reg_index)
|
||||
m_register_values.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPlanAssemblyTracer::TracingEnded ()
|
||||
{
|
||||
for (uint32_t reg_index = 0, num_registers = m_register_values.size();
|
||||
reg_index < num_registers;
|
||||
++reg_index)
|
||||
m_register_values[reg_index] = 0;
|
||||
}
|
||||
|
||||
static const char *Padding(int length)
|
||||
{
|
||||
const int padding_size = 256;
|
||||
|
||||
static char* padding = NULL;
|
||||
static int prev_length = 256;
|
||||
|
||||
if (!padding) {
|
||||
padding = new char[padding_size];
|
||||
memset(padding, ' ', padding_size);
|
||||
}
|
||||
|
||||
if (length > 255)
|
||||
length = 255;
|
||||
|
||||
if (prev_length < 256)
|
||||
padding[prev_length] = ' ';
|
||||
|
||||
padding[length] = '\0';
|
||||
|
||||
prev_length = length;
|
||||
|
||||
return padding;
|
||||
}
|
||||
|
||||
static void PadOutTo(StreamString &stream, int target)
|
||||
{
|
||||
stream.Flush();
|
||||
|
||||
int length = stream.GetString().length();
|
||||
|
||||
if (length + 1 < target)
|
||||
stream.PutCString(Padding(target - (length + 1)));
|
||||
|
||||
stream.PutCString(" ");
|
||||
}
|
||||
|
||||
void ThreadPlanAssemblyTracer::Log ()
|
||||
{
|
||||
Stream *stream = GetLogStream ();
|
||||
|
||||
if (!stream)
|
||||
return;
|
||||
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext();
|
||||
|
||||
lldb::addr_t pc = reg_ctx->GetPC();
|
||||
Address pc_addr;
|
||||
bool addr_valid = false;
|
||||
|
||||
StreamString desc;
|
||||
|
||||
int desired_width = 0;
|
||||
|
||||
addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, pc_addr);
|
||||
|
||||
pc_addr.Dump(&desc, &m_thread, Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress);
|
||||
|
||||
desired_width += 64;
|
||||
PadOutTo(desc, desired_width);
|
||||
|
||||
if (m_disassembler)
|
||||
{
|
||||
bzero(m_buffer_sp->GetBytes(), m_buffer_sp->GetByteSize());
|
||||
|
||||
Error err;
|
||||
m_process.ReadMemory(pc, m_buffer_sp->GetBytes(), m_buffer_sp->GetByteSize(), err);
|
||||
|
||||
if (err.Success())
|
||||
{
|
||||
DataExtractor extractor(m_buffer_sp,
|
||||
m_process.GetByteOrder(),
|
||||
m_process.GetAddressByteSize());
|
||||
|
||||
if (addr_valid)
|
||||
m_disassembler->DecodeInstructions (pc_addr, extractor, 0, 1);
|
||||
else
|
||||
m_disassembler->DecodeInstructions (Address (NULL, pc), extractor, 0, 1);
|
||||
|
||||
InstructionList &instruction_list = m_disassembler->GetInstructionList();
|
||||
|
||||
if (instruction_list.GetSize())
|
||||
{
|
||||
Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get();
|
||||
instruction->Dump (&desc,
|
||||
false,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
desired_width += 32;
|
||||
PadOutTo(desc, desired_width);
|
||||
}
|
||||
|
||||
if (m_abi && m_intptr_type.GetOpaqueQualType())
|
||||
{
|
||||
ValueList value_list;
|
||||
const int num_args = 1;
|
||||
|
||||
for (int arg_index = 0; arg_index < num_args; ++arg_index)
|
||||
{
|
||||
Value value;
|
||||
value.SetValueType (Value::eValueTypeScalar);
|
||||
value.SetContext (Value::eContextTypeOpaqueClangQualType, m_intptr_type.GetOpaqueQualType());
|
||||
value_list.PushValue (value);
|
||||
}
|
||||
|
||||
if (m_abi->GetArgumentValues (m_thread, value_list))
|
||||
{
|
||||
for (int arg_index = 0; arg_index < num_args; ++arg_index)
|
||||
{
|
||||
desc.Printf("arg[%d]=%llx", arg_index, value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
|
||||
|
||||
if (arg_index + 1 < num_args)
|
||||
desc.Printf(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
desired_width += 20;
|
||||
PadOutTo(desc, desired_width);
|
||||
|
||||
for (uint32_t reg_index = 0, num_registers = reg_ctx->GetRegisterCount();
|
||||
reg_index < num_registers;
|
||||
++reg_index)
|
||||
{
|
||||
uint64_t reg_value = reg_ctx->ReadRegisterAsUnsigned(reg_index, 0x0);
|
||||
|
||||
if (reg_value != m_register_values[reg_index])
|
||||
{
|
||||
desc.Printf ("%s:0x%llx->0x%llx ", reg_ctx->GetRegisterName(reg_index), m_register_values[reg_index], reg_value);
|
||||
|
||||
m_register_values[reg_index] = reg_value;
|
||||
}
|
||||
}
|
||||
|
||||
stream->Printf ("Single-step: %s", desc.GetString().c_str());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue