[Lldb-commits] [lldb] r118270 - in /lldb/trunk/source: Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp Target/ThreadPlanStepInRange.cpp Target/ThreadPlanStepOverRange.cpp
Jim Ingham
jingham at apple.com
Thu Nov 4 17:18:21 PDT 2010
Author: jingham
Date: Thu Nov 4 19:18:21 2010
New Revision: 118270
URL: http://llvm.org/viewvc/llvm-project?rev=118270&view=rev
Log:
Handle stepping through ObjC vtable trampoline code.
Modified:
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h
lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
lldb/trunk/source/Target/ThreadPlanStepInRange.cpp
lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp
Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp?rev=118270&r1=118269&r2=118270&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp Thu Nov 4 19:18:21 2010
@@ -15,7 +15,9 @@
// Project includes
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/FileSpec.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
@@ -33,6 +35,351 @@
using namespace lldb;
using namespace lldb_private;
+
+AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr) :
+ m_valid (true),
+ m_owner(owner),
+ m_header_addr (header_addr),
+ m_code_start_addr(0),
+ m_code_end_addr (0),
+ m_next_region (0)
+{
+ SetUpRegion ();
+}
+
+void
+AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion()
+{
+ // The header looks like:
+ //
+ // uint16_t headerSize
+ // uint16_t descSize
+ // uint32_t descCount
+ // void * next
+ //
+ // First read in the header:
+
+ char memory_buffer[16];
+ Process *process = m_owner->GetProcess();
+ DataExtractor data(memory_buffer, sizeof(memory_buffer),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ size_t actual_size = 8 + process->GetAddressByteSize();
+ Error error;
+ size_t bytes_read = process->ReadMemory (m_header_addr, memory_buffer, actual_size, error);
+ if (bytes_read != actual_size)
+ {
+ m_valid = false;
+ return;
+ }
+
+ uint32_t offset_ptr = 0;
+ uint16_t header_size = data.GetU16(&offset_ptr);
+ uint16_t descriptor_size = data.GetU16(&offset_ptr);
+ size_t num_descriptors = data.GetU32(&offset_ptr);
+
+ m_next_region = data.GetPointer(&offset_ptr);
+
+ // If the header size is 0, that means we've come in too early before this data is set up.
+ // Set ourselves as not valid, and continue.
+ if (header_size == 0)
+ {
+ m_valid = false;
+ return;
+ }
+
+ // Now read in all the descriptors:
+ // The descriptor looks like:
+ //
+ // uint32_t offset
+ // uint32_t flags
+ //
+ // Where offset is either 0 - in which case it is unused, or
+ // it is the offset of the vtable code from the beginning of the descriptor record.
+ // Below, we'll convert that into an absolute code address, since I don't want to have
+ // to compute it over and over.
+
+ // Ingest the whole descriptor array:
+ lldb::addr_t desc_ptr = m_header_addr + header_size;
+ size_t desc_array_size = num_descriptors * descriptor_size;
+ DataBufferSP data_sp(new DataBufferHeap (desc_array_size, '\0'));
+ uint8_t* dst = (uint8_t*)data_sp->GetBytes();
+
+ DataExtractor desc_extractor (dst, desc_array_size,
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ bytes_read = process->ReadMemory(desc_ptr, dst, desc_array_size, error);
+ if (bytes_read != desc_array_size)
+ {
+ m_valid = false;
+ return;
+ }
+
+ // The actual code for the vtables will be laid out consecutively, so I also
+ // compute the start and end of the whole code block.
+
+ offset_ptr = 0;
+ m_code_start_addr = 0;
+ m_code_end_addr = 0;
+
+ for (int i = 0; i < num_descriptors; i++)
+ {
+ lldb::addr_t start_offset = offset_ptr;
+ uint32_t offset = desc_extractor.GetU32 (&offset_ptr);
+ uint32_t flags = desc_extractor.GetU32 (&offset_ptr);
+ lldb:addr_t code_addr = desc_ptr + start_offset + offset;
+ m_descriptors.push_back (VTableDescriptor(flags, code_addr));
+
+ if (m_code_start_addr == 0 || code_addr < m_code_start_addr)
+ m_code_start_addr = code_addr;
+ if (code_addr > m_code_end_addr)
+ m_code_end_addr = code_addr;
+
+ offset_ptr = start_offset + descriptor_size;
+ }
+ // Finally, a little bird told me that all the vtable code blocks are the same size.
+ // Let's compute the blocks and if they are all the same add the size to the code end address:
+ lldb::addr_t code_size = 0;
+ bool all_the_same = true;
+ for (int i = 0; i < num_descriptors - 1; i++)
+ {
+ lldb::addr_t this_size = m_descriptors[i + 1].code_start - m_descriptors[i].code_start;
+ if (code_size == 0)
+ code_size = this_size;
+ else
+ {
+ if (this_size != code_size)
+ all_the_same = false;
+ if (this_size > code_size)
+ code_size = this_size;
+ }
+ }
+ if (all_the_same)
+ m_code_end_addr += code_size;
+}
+
+bool
+AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::AddressInRegion (lldb::addr_t addr, uint32_t &flags)
+{
+ if (!IsValid())
+ return false;
+
+ if (addr < m_code_start_addr || addr > m_code_end_addr)
+ return false;
+
+ std::vector<VTableDescriptor>::iterator pos, end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; pos++)
+ {
+ if (addr <= (*pos).code_start)
+ {
+ flags = (*pos).flags;
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::Dump (Stream &s)
+{
+ s.Printf ("Header addr: 0x%llx Code start: 0x%llx Code End: 0x%llx Next: 0x%llx\n",
+ m_header_addr, m_code_start_addr, m_code_end_addr, m_next_region);
+ size_t num_elements = m_descriptors.size();
+ for (size_t i = 0; i < num_elements; i++)
+ {
+ s.Indent();
+ s.Printf ("Code start: 0x%llx Flags: %d\n", m_descriptors[i].code_start, m_descriptors[i].flags);
+ }
+}
+
+AppleObjCTrampolineHandler::AppleObjCVTables::AppleObjCVTables (ProcessSP &process_sp, ModuleSP &objc_module_sp) :
+ m_process_sp(process_sp),
+ m_trampoline_header(LLDB_INVALID_ADDRESS),
+ m_trampolines_changed_bp_id(LLDB_INVALID_BREAK_ID),
+ m_objc_module_sp(objc_module_sp)
+{
+
+}
+
+AppleObjCTrampolineHandler::AppleObjCVTables::~AppleObjCVTables()
+{
+ if (m_trampolines_changed_bp_id != LLDB_INVALID_BREAK_ID)
+ m_process_sp->GetTarget().RemoveBreakpointByID (m_trampolines_changed_bp_id);
+}
+
+bool
+AppleObjCTrampolineHandler::AppleObjCVTables::InitializeVTableSymbols ()
+{
+ if (m_trampoline_header != LLDB_INVALID_ADDRESS)
+ return true;
+ Target &target = m_process_sp->GetTarget();
+
+ ModuleList &modules = target.GetImages();
+ size_t num_modules = modules.GetSize();
+ if (!m_objc_module_sp)
+ {
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ if (m_process_sp->GetObjCLanguageRuntime()->IsModuleObjCLibrary (modules.GetModuleAtIndex(i)))
+ {
+ m_objc_module_sp = modules.GetModuleAtIndex(i);
+ break;
+ }
+ }
+ }
+
+ if (m_objc_module_sp)
+ {
+ ConstString trampoline_name ("gdb_objc_trampolines");
+ const Symbol *trampoline_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType(trampoline_name,
+ eSymbolTypeData);
+ if (trampoline_symbol != NULL)
+ {
+ const Address &temp_address = trampoline_symbol->GetValue();
+ if (!temp_address.IsValid())
+ return false;
+
+ m_trampoline_header = temp_address.GetLoadAddress(&target);
+ if (m_trampoline_header == LLDB_INVALID_ADDRESS)
+ return false;
+
+ // Next look up the "changed" symbol and set a breakpoint on that...
+ ConstString changed_name ("gdb_objc_trampolines_changed");
+ const Symbol *changed_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType(changed_name,
+ eSymbolTypeCode);
+ if (changed_symbol != NULL)
+ {
+ const Address &temp_address = changed_symbol->GetValue();
+ if (!temp_address.IsValid())
+ return false;
+
+ lldb::addr_t changed_addr = temp_address.GetLoadAddress(&target);
+ if (changed_addr != LLDB_INVALID_ADDRESS)
+ {
+ BreakpointSP trampolines_changed_bp_sp = target.CreateBreakpoint (changed_addr,
+ true);
+ if (trampolines_changed_bp_sp != NULL)
+ {
+ m_trampolines_changed_bp_id = trampolines_changed_bp_sp->GetID();
+ trampolines_changed_bp_sp->SetCallback (RefreshTrampolines, this, true);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ AppleObjCVTables *vtable_handler = (AppleObjCVTables *) baton;
+ if (vtable_handler->InitializeVTableSymbols())
+ {
+ // The Update function is called with the address of an added region. So we grab that address, and
+ // feed it into ReadRegions. Of course, our friend the ABI will get the values for us.
+ Process *process = context->exe_ctx.process;
+ const ABI *abi = process->GetABI();
+
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ValueList argument_values;
+ Value input_value;
+ void *clang_void_ptr_type = clang_ast_context->GetVoidPtrType(false);
+ input_value.SetValueType (Value::eValueTypeScalar);
+ input_value.SetContext (Value::eContextTypeOpaqueClangQualType, clang_void_ptr_type);
+ argument_values.PushValue(input_value);
+
+ bool success = abi->GetArgumentValues (*(context->exe_ctx.thread), argument_values);
+ if (!success)
+ return false;
+
+ // Now get a pointer value from the zeroth argument.
+ Error error;
+ DataExtractor data;
+ error = argument_values.GetValueAtIndex(0)->GetValueAsData(&(context->exe_ctx), clang_ast_context->getASTContext(), data, 0);
+ uint32_t offset_ptr = 0;
+ lldb::addr_t region_addr = data.GetPointer(&offset_ptr);
+
+ if (region_addr != 0)
+ vtable_handler->ReadRegions(region_addr);
+ }
+ return false;
+}
+
+bool
+AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions ()
+{
+ // The no argument version reads the start region from the value of the gdb_regions_header, and
+ // gets started from there.
+
+ m_regions.clear();
+ if (!InitializeVTableSymbols())
+ return false;
+ char memory_buffer[8];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer),
+ m_process_sp->GetByteOrder(),
+ m_process_sp->GetAddressByteSize());
+ Error error;
+ size_t bytes_read = m_process_sp->ReadMemory (m_trampoline_header, memory_buffer, m_process_sp->GetAddressByteSize(), error);
+ if (bytes_read != m_process_sp->GetAddressByteSize())
+ return false;
+
+ uint32_t offset_ptr = 0;
+ lldb::addr_t region_addr = data.GetPointer(&offset_ptr);
+ return ReadRegions (region_addr);
+}
+
+bool
+AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions (lldb::addr_t region_addr)
+{
+ if (!m_process_sp)
+ return false;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+
+ // We aren't starting at the trampoline symbol.
+ InitializeVTableSymbols ();
+ lldb::addr_t next_region = region_addr;
+
+ // Read in the sizes of the headers.
+ while (next_region != 0)
+ {
+ m_regions.push_back (VTableRegion(this, next_region));
+ if (!m_regions.back().IsValid())
+ {
+ m_regions.clear();
+ return false;
+ }
+ if (log)
+ {
+ StreamString s;
+ m_regions.back().Dump(s);
+ log->Printf("Read vtable region: \n%s", s.GetData());
+ }
+
+ next_region = m_regions.back().GetNextRegionAddr();
+ }
+
+ return true;
+}
+
+bool
+AppleObjCTrampolineHandler::AppleObjCVTables::IsAddressInVTables (lldb::addr_t addr, uint32_t &flags)
+{
+ region_collection::iterator pos, end = m_regions.end();
+ for (pos = m_regions.begin(); pos != end; pos++)
+ {
+ if ((*pos).AddressInRegion (addr, flags))
+ return true;
+ }
+ return false;
+}
+
const AppleObjCTrampolineHandler::DispatchFunction
AppleObjCTrampolineHandler::g_dispatch_functions[] =
{
@@ -60,24 +407,9 @@
{NULL}
};
-bool
-AppleObjCTrampolineHandler::ModuleIsObjCLibrary (const ModuleSP &module_sp)
-{
- const FileSpec &module_file_spec = module_sp->GetFileSpec();
- static ConstString ObjCName ("libobjc.A.dylib");
-
- if (module_file_spec)
- {
- if (module_file_spec.GetFilename() == ObjCName)
- return true;
- }
-
- return false;
-}
-
-AppleObjCTrampolineHandler::AppleObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module) :
+AppleObjCTrampolineHandler::AppleObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module_sp) :
m_process_sp (process_sp),
- m_objc_module_sp (objc_module),
+ m_objc_module_sp (objc_module_sp),
m_impl_fn_addr (LLDB_INVALID_ADDRESS),
m_impl_stret_fn_addr (LLDB_INVALID_ADDRESS)
{
@@ -119,6 +451,11 @@
m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i));
}
}
+
+ // Build our vtable dispatch handler here:
+ m_vtables_ap.reset(new AppleObjCVTables(process_sp, m_objc_module_sp));
+ if (m_vtables_ap.get())
+ m_vtables_ap->ReadRegions();
}
ThreadPlanSP
@@ -127,13 +464,38 @@
ThreadPlanSP ret_plan_sp;
lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC();
+ DispatchFunction this_dispatch;
+ bool found_it = false;
+
MsgsendMap::iterator pos;
pos = m_msgSend_map.find (curr_pc);
if (pos != m_msgSend_map.end())
{
+ this_dispatch = g_dispatch_functions[(*pos).second];
+ found_it = true;
+ }
+
+ if (!found_it)
+ {
+ uint32_t flags;
+ if (m_vtables_ap.get())
+ {
+ found_it = m_vtables_ap->IsAddressInVTables (curr_pc, flags);
+ if (found_it)
+ {
+ this_dispatch.name = "vtable";
+ this_dispatch.stret_return
+ = (flags & AppleObjCVTables::eOBJC_TRAMPOLINE_STRET) == AppleObjCVTables::eOBJC_TRAMPOLINE_STRET;
+ this_dispatch.is_super = false;
+ this_dispatch.fixedup = DispatchFunction::eFixUpFixed;
+ }
+ }
+ }
+
+ if (found_it)
+ {
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
- const DispatchFunction *this_dispatch = &g_dispatch_functions[(*pos).second];
lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0);
@@ -161,7 +523,7 @@
// If this is a struct return dispatch, then the first argument is the
// return struct pointer, and the object is the second, and the selector is the third.
// Otherwise the object is the first and the selector the second.
- if (this_dispatch->stret_return)
+ if (this_dispatch.stret_return)
{
obj_index = 1;
sel_index = 2;
@@ -197,7 +559,7 @@
isa_value.SetValueType(Value::eValueTypeLoadAddress);
isa_value.ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
- if (this_dispatch->fixedup == DispatchFunction::eFixUpFixed)
+ if (this_dispatch.fixedup == DispatchFunction::eFixUpFixed)
{
// For the FixedUp method the Selector is actually a pointer to a
// structure, the second field of which is the selector number.
@@ -206,7 +568,7 @@
sel_value->SetValueType(Value::eValueTypeLoadAddress);
sel_value->ResolveValue(&exec_ctx, clang_ast_context->getASTContext());
}
- else if (this_dispatch->fixedup == DispatchFunction::eFixUpToFix)
+ else if (this_dispatch.fixedup == DispatchFunction::eFixUpToFix)
{
// FIXME: If the method dispatch is not "fixed up" then the selector is actually a
// pointer to the string name of the selector. We need to look that up...
@@ -219,7 +581,7 @@
// FIXME: If this is a dispatch to the super-class, we need to get the super-class from
// the class, and disaptch to that instead.
// But for now I just punt and return no plan.
- if (this_dispatch->is_super)
+ if (this_dispatch.is_super)
{
if (log)
log->Printf ("Punting on stepping into super method dispatch.");
@@ -244,7 +606,7 @@
if (impl_addr == LLDB_INVALID_ADDRESS)
{
- Address resolve_address(NULL, this_dispatch->stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr);
+ Address resolve_address(NULL, this_dispatch.stret_return ? m_impl_stret_fn_addr : m_impl_fn_addr);
StreamString errors;
{
@@ -289,6 +651,12 @@
dispatch_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
dispatch_values.GetValueAtIndex(1)->GetScalar().ULongLong(),
stop_others));
+ if (log)
+ {
+ StreamString s;
+ ret_plan_sp->GetDescription(&s, eDescriptionLevelFull);
+ log->Printf("Using ObjC step plan: %s.\n", s.GetData());
+ }
}
else
{
Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h?rev=118270&r1=118269&r2=118270&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h Thu Nov 4 19:18:21 2010
@@ -31,9 +31,7 @@
AppleObjCTrampolineHandler (ProcessSP process_sp, ModuleSP objc_module_sp);
~AppleObjCTrampolineHandler() {}
-
- static bool ModuleIsObjCLibrary (const ModuleSP &module_sp);
-
+
ThreadPlanSP
GetStepThroughDispatchPlan (Thread &thread, bool stop_others);
@@ -57,6 +55,127 @@
};
private:
+
+ class AppleObjCVTables
+ {
+ public:
+ // These come from objc-gdb.h.
+ enum VTableFlags
+ {
+ eOBJC_TRAMPOLINE_MESSAGE = (1<<0), // trampoline acts like objc_msgSend
+ eOBJC_TRAMPOLINE_STRET = (1<<1), // trampoline is struct-returning
+ eOBJC_TRAMPOLINE_VTABLE = (1<<2), // trampoline is vtable dispatcher
+ };
+
+ private:
+ struct VTableDescriptor
+ {
+ VTableDescriptor(uint32_t in_flags, addr_t in_code_start) :
+ flags(in_flags),
+ code_start(in_code_start) {}
+
+ uint32_t flags;
+ lldb::addr_t code_start;
+ };
+
+
+ class VTableRegion
+ {
+ public:
+ VTableRegion() :
+ m_valid (false),
+ m_owner (NULL),
+ m_header_addr (LLDB_INVALID_ADDRESS),
+ m_code_start_addr(0),
+ m_code_end_addr (0),
+ m_next_region (0)
+ {}
+
+ VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr);
+
+ void SetUpRegion();
+
+ lldb::addr_t GetNextRegionAddr ()
+ {
+ return m_next_region;
+ }
+
+ lldb::addr_t
+ GetCodeStart ()
+ {
+ return m_code_start_addr;
+ }
+
+ lldb::addr_t
+ GetCodeEnd ()
+ {
+ return m_code_end_addr;
+ }
+
+ uint32_t
+ GetFlagsForVTableAtAddress (lldb::addr_t address)
+ {
+ return 0;
+ }
+
+ bool
+ IsValid ()
+ {
+ return m_valid;
+ }
+
+ bool
+ AddressInRegion (lldb::addr_t addr, uint32_t &flags);
+
+ void
+ Dump (Stream &s);
+
+ public:
+ bool m_valid;
+ AppleObjCVTables *m_owner;
+ lldb::addr_t m_header_addr;
+ lldb::addr_t m_code_start_addr;
+ lldb::addr_t m_code_end_addr;
+ std::vector<VTableDescriptor> m_descriptors;
+ lldb::addr_t m_next_region;
+ };
+
+ public:
+ AppleObjCVTables(ProcessSP &process_sp, ModuleSP &objc_module_sp);
+
+ ~AppleObjCVTables();
+
+ bool
+ InitializeVTableSymbols ();
+
+ static bool RefreshTrampolines (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+ bool
+ ReadRegions ();
+
+ bool
+ ReadRegions (lldb::addr_t region_addr);
+
+ bool
+ IsAddressInVTables (lldb::addr_t addr, uint32_t &flags);
+
+ Process *GetProcess ()
+ {
+ return m_process_sp.get();
+ }
+
+ private:
+ ProcessSP m_process_sp;
+ typedef std::vector<VTableRegion> region_collection;
+ lldb::addr_t m_trampoline_header;
+ lldb::break_id_t m_trampolines_changed_bp_id;
+ region_collection m_regions;
+ lldb::ModuleSP m_objc_module_sp;
+
+ };
+
static const DispatchFunction g_dispatch_functions[];
typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch fn address to the index in g_dispatch_functions
@@ -68,6 +187,7 @@
Mutex m_impl_function_mutex;
lldb::addr_t m_impl_fn_addr;
lldb::addr_t m_impl_stret_fn_addr;
+ std::auto_ptr<AppleObjCVTables> m_vtables_ap;
};
Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp?rev=118270&r1=118269&r2=118270&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp Thu Nov 4 19:18:21 2010
@@ -115,6 +115,13 @@
lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
Address target_address(NULL, target_addr);
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (target_addr == 0)
+ {
+ if (log)
+ log->Printf("Got target implementation of 0x0, stopping.");
+ SetPlanComplete();
+ return true;
+ }
if (log)
log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
Modified: lldb/trunk/source/Target/ThreadPlanStepInRange.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepInRange.cpp?rev=118270&r1=118269&r2=118270&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepInRange.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepInRange.cpp Thu Nov 4 19:18:21 2010
@@ -83,23 +83,6 @@
if (InRange())
return false;
- // If we're in an older frame then we should stop.
- if (FrameIsOlder())
- return true;
-
- // See if we are in a place we should step through (i.e. a trampoline of some sort):
- // One tricky bit here is that some stubs don't push a frame, so we have to check
- // both the case of a frame that is younger, or the same as this frame.
- // However, if the frame is the same, and we are still in the symbol we started
- // in, the we don't need to do this. This first check isn't strictly necessary,
- // but it is more efficient.
-
- if (!FrameIsYounger() && InSymbol())
- {
- SetPlanComplete();
- return true;
- }
-
ThreadPlan* new_plan = NULL;
// Stepping through should be done stopping other threads in general, since we're setting a breakpoint and
@@ -111,7 +94,39 @@
else
stop_others = false;
- new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+ if (FrameIsOlder())
+ {
+ // If we're in an older frame then we should stop.
+ //
+ // A caveat to this is if we think the frame is older but we're actually in a trampoline.
+ // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
+ // in a trampoline we think the frame is older because the trampoline confused the backtracer.
+ new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+ if (new_plan == NULL)
+ return true;
+ else if (log)
+ {
+ log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
+ }
+
+ }
+ else if (!FrameIsYounger() && InSymbol())
+ {
+ // If we are not in a place we should step through, we're done.
+ // One tricky bit here is that some stubs don't push a frame, so we have to check
+ // both the case of a frame that is younger, or the same as this frame.
+ // However, if the frame is the same, and we are still in the symbol we started
+ // in, the we don't need to do this. This first check isn't strictly necessary,
+ // but it is more efficient.
+
+ SetPlanComplete();
+ return true;
+ }
+
+ // We may have set the plan up above in the FrameIsOlder section:
+
+ if (new_plan == NULL)
+ new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
if (log)
{
Modified: lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp?rev=118270&r1=118269&r2=118270&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanStepOverRange.cpp Thu Nov 4 19:18:21 2010
@@ -88,7 +88,19 @@
ThreadPlan* new_plan = NULL;
if (FrameIsOlder())
- return true;
+ {
+ // If we're in an older frame then we should stop.
+ //
+ // A caveat to this is if we think the frame is older but we're actually in a trampoline.
+ // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
+ // in a trampoline we think the frame is older because the trampoline confused the backtracer.
+ // As below, we step through first, and then try to figure out how to get back out again.
+
+ new_plan = m_thread.QueueThreadPlanForStepThrough (false, stop_others);
+
+ if (new_plan != NULL && log)
+ log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
+ }
else if (FrameIsYounger())
{
new_plan = m_thread.QueueThreadPlanForStepOut (false, NULL, true, stop_others, lldb::eVoteNo, lldb::eVoteNoOpinion);
More information about the lldb-commits
mailing list