diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index e82d6eacf7a8..749ff8d1a09c 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -612,12 +612,30 @@ protected: /// Only the Target can make a breakpoint, and it owns the breakpoint lifespans. /// The constructor takes a filter and a resolver. Up in Target there are convenience /// variants that make breakpoints for some common cases. + /// + /// @param[in] target + /// The target in which the breakpoint will be set. + /// + /// @param[in] filter_sp + /// Shared pointer to the search filter that restricts the search domain of the breakpoint. + /// + /// @param[in] resolver_sp + /// Shared pointer to the resolver object that will determine breakpoint matches. + /// + /// @param hardware + /// If true, request a hardware breakpoint to be used to implement the breakpoint locations. + /// + /// @param resolve_indirect_symbols + /// If true, and the address of a given breakpoint location in this breakpoint is set on an + /// indirect symbol (i.e. Symbol::IsIndirect returns true) then the actual breakpoint site will + /// be set on the target of the indirect symbol. //------------------------------------------------------------------ // This is the generic constructor Breakpoint(Target &target, lldb::SearchFilterSP &filter_sp, lldb::BreakpointResolverSP &resolver_sp, - bool hardware); + bool hardware, + bool resolve_indirect_symbols = true); friend class BreakpointLocation; // To call the following two when determining whether to stop. @@ -643,6 +661,7 @@ private: BreakpointOptions m_options; // Settable breakpoint options BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint. std::string m_kind_description; + bool m_resolve_indirect_symbols; void SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind); diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h index f4ba21a385f8..ac4c28bb6e5f 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -321,7 +321,59 @@ public: //------------------------------------------------------------------ bool InvokeCallback (StoppointCallbackContext *context); + + //------------------------------------------------------------------ + /// Returns whether we should resolve Indirect functions in setting the breakpoint site + /// for this location. + /// + /// @return + /// \b true if the breakpoint SITE for this location should be set on the + /// resolved location for Indirect functions. + //------------------------------------------------------------------ + bool + ShouldResolveIndirectFunctions () + { + return m_should_resolve_indirect_functions; + } + //------------------------------------------------------------------ + /// Returns whether the address set in the breakpoint site for this location was found by resolving + /// an indirect symbol. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool + IsIndirect () + { + return m_is_indirect; + } + + void + SetIsIndirect (bool is_indirect) + { + m_is_indirect = is_indirect; + } + + //------------------------------------------------------------------ + /// Returns whether the address set in the breakpoint location was re-routed to the target of a + /// re-exported symbol. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool + IsReExported () + { + return m_is_reexported; + } + + void + SetIsReExported (bool is_reexported) + { + m_is_reexported = is_reexported; + } + protected: friend class BreakpointLocationList; friend class Process; @@ -375,12 +427,16 @@ private: Breakpoint &owner, const Address &addr, lldb::tid_t tid, - bool hardware); - + bool hardware, + bool check_for_resolver = true); + //------------------------------------------------------------------ // Data members: //------------------------------------------------------------------ bool m_being_created; + bool m_should_resolve_indirect_functions; + bool m_is_reexported; + bool m_is_indirect; Address m_address; ///< The address defining this location. Breakpoint &m_owner; ///< The breakpoint that produced this object. std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options. @@ -389,6 +445,12 @@ private: Mutex m_condition_mutex; ///< Guards parsing and evaluation of the condition, which could be evaluated by multiple processes. size_t m_condition_hash; ///< For testing whether the condition source code changed. + void + SetShouldResolveIndirectFunctions (bool do_resolve) + { + m_should_resolve_indirect_functions = do_resolve; + } + void SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind); diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h index b25208659c7f..ec34641b727c 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h +++ b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h @@ -236,7 +236,7 @@ protected: /// Returns breakpoint location id. //------------------------------------------------------------------ lldb::BreakpointLocationSP - Create (const Address &addr); + Create (const Address &addr, bool resolve_indirect_symbols); void StartRecordingNewLocations(BreakpointLocationCollection &new_locations); @@ -246,6 +246,7 @@ protected: lldb::BreakpointLocationSP AddLocation (const Address &addr, + bool resolve_indirect_symbols, bool *new_location = NULL); bool diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index a1da6a39e35a..fd1dd5ed4f26 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2986,11 +2986,7 @@ public: //------------------------------------------------------------------ virtual lldb::addr_t - ResolveIndirectFunction(const Address *address, Error &error) - { - error.SetErrorStringWithFormat("error: %s does not support indirect functions in the debug process", GetPluginName().GetCString()); - return LLDB_INVALID_ADDRESS; - } + ResolveIndirectFunction(const Address *address, Error &error); virtual Error GetMemoryRegionInfo (lldb::addr_t load_addr, @@ -3670,6 +3666,12 @@ protected: { return IS_VALID_LLDB_HOST_THREAD(m_private_state_thread); } + + void + ForceNextEventDelivery() + { + m_force_next_event_delivery = true; + } //------------------------------------------------------------------ // Type definitions @@ -3744,7 +3746,9 @@ protected: bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check. bool m_finalize_called; bool m_clear_thread_plans_on_stop; + bool m_force_next_event_delivery; lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent. + std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses; bool m_destroy_in_process; enum { diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 084aa68424e7..e20e72d9cb5e 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -637,7 +637,8 @@ public: CreateBreakpoint (lldb::SearchFilterSP &filter_sp, lldb::BreakpointResolverSP &resolver_sp, bool internal, - bool request_hardware); + bool request_hardware, + bool resolve_indirect_symbols); // Use this to create a watchpoint: lldb::WatchpointSP diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index 32c0b1066f8e..5ce064fc41a0 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -45,14 +45,19 @@ Breakpoint::GetEventIdentifier () //---------------------------------------------------------------------- // Breakpoint constructor //---------------------------------------------------------------------- -Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool hardware) : +Breakpoint::Breakpoint(Target &target, + SearchFilterSP &filter_sp, + BreakpointResolverSP &resolver_sp, + bool hardware, + bool resolve_indirect_symbols) : m_being_created(true), m_hardware(hardware), m_target (target), m_filter_sp (filter_sp), m_resolver_sp (resolver_sp), m_options (), - m_locations (*this) + m_locations (*this), + m_resolve_indirect_symbols(resolve_indirect_symbols) { m_being_created = false; } @@ -87,7 +92,7 @@ Breakpoint::GetTarget () const BreakpointLocationSP Breakpoint::AddLocation (const Address &addr, bool *new_location) { - return m_locations.AddLocation (addr, new_location); + return m_locations.AddLocation (addr, m_resolve_indirect_symbols, new_location); } BreakpointLocationSP diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index 5009e862d84b..2c75a11e9788 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -39,16 +39,29 @@ BreakpointLocation::BreakpointLocation Breakpoint &owner, const Address &addr, lldb::tid_t tid, - bool hardware + bool hardware, + bool check_for_resolver ) : StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware), m_being_created(true), + m_should_resolve_indirect_functions (false), + m_is_reexported (false), + m_is_indirect (false), m_address (addr), m_owner (owner), m_options_ap (), m_bp_site_sp (), m_condition_mutex () { + if (check_for_resolver) + { + Symbol *symbol = m_address.CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) + { + SetShouldResolveIndirectFunctions (true); + } + } + SetThreadID (tid); m_being_created = false; } @@ -545,7 +558,10 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial) { - s->PutCString("where = "); + if (IsReExported()) + s->PutCString ("re-exported target = "); + else + s->PutCString("where = "); sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false); } else @@ -584,7 +600,10 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) if (sc.symbol) { s->EOL(); - s->Indent("symbol = "); + if (IsReExported()) + s->Indent ("re-exported target = "); + else + s->Indent("symbol = "); s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>")); } } @@ -612,6 +631,24 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); else m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); + + if (IsIndirect() && m_bp_site_sp) + { + Address resolved_address; + resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target); + Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol(); + if (resolved_symbol) + { + if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial) + s->Printf (", "); + else if (level == lldb::eDescriptionLevelVerbose) + { + s->EOL(); + s->Indent(); + } + s->Printf ("indirect target = %s", resolved_symbol->GetName().GetCString()); + } + } if (level == lldb::eDescriptionLevelVerbose) { diff --git a/lldb/source/Breakpoint/BreakpointLocationList.cpp b/lldb/source/Breakpoint/BreakpointLocationList.cpp index 39b8d922585e..917c776e75d2 100644 --- a/lldb/source/Breakpoint/BreakpointLocationList.cpp +++ b/lldb/source/Breakpoint/BreakpointLocationList.cpp @@ -41,12 +41,12 @@ BreakpointLocationList::~BreakpointLocationList() } BreakpointLocationSP -BreakpointLocationList::Create (const Address &addr) +BreakpointLocationList::Create (const Address &addr, bool resolve_indirect_symbols) { Mutex::Locker locker (m_mutex); // The location ID is just the size of the location list + 1 lldb::break_id_t bp_loc_id = ++m_next_id; - BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware())); + BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware(), resolve_indirect_symbols)); m_locations.push_back (bp_loc_sp); m_address_to_location[addr] = bp_loc_sp; return bp_loc_sp; @@ -247,7 +247,7 @@ BreakpointLocationList::GetDescription (Stream *s, lldb::DescriptionLevel level) } BreakpointLocationSP -BreakpointLocationList::AddLocation (const Address &addr, bool *new_location) +BreakpointLocationList::AddLocation (const Address &addr, bool resolve_indirect_symbols, bool *new_location) { Mutex::Locker locker (m_mutex); @@ -256,7 +256,7 @@ BreakpointLocationList::AddLocation (const Address &addr, bool *new_location) BreakpointLocationSP bp_loc_sp (FindByAddress(addr)); if (!bp_loc_sp) { - bp_loc_sp = Create (addr); + bp_loc_sp = Create (addr, resolve_indirect_symbols); if (bp_loc_sp) { bp_loc_sp->ResolveBreakpointSite(); diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index c82dd5ee050b..cf5d89cb7a8b 100644 --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -272,6 +272,8 @@ BreakpointResolverName::SearchCallback { if (func_list.GetContextAtIndex(i, sc)) { + bool is_reexported = false; + if (sc.block && sc.block->GetInlinedFunctionInfo()) { if (!sc.block->GetStartAddress(break_addr)) @@ -293,7 +295,10 @@ BreakpointResolverName::SearchCallback { const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget()); if (actual_symbol) + { + is_reexported = true; break_addr = actual_symbol->GetAddress(); + } } else { @@ -313,6 +318,7 @@ BreakpointResolverName::SearchCallback if (filter.AddressPasses(break_addr)) { BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location)); + bp_loc_sp->SetIsReExported(is_reexported); if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) { if (log) diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp index 3b97253d0402..5ac2bcce70f0 100644 --- a/lldb/source/Core/Address.cpp +++ b/lldb/source/Core/Address.cpp @@ -328,15 +328,27 @@ Address::GetLoadAddress (Target *target) const addr_t Address::GetCallableLoadAddress (Target *target, bool is_indirect) const { - if (is_indirect && target) { + addr_t code_addr = LLDB_INVALID_ADDRESS; + + if (is_indirect && target) + { ProcessSP processSP = target->GetProcessSP(); Error error; if (processSP.get()) - return processSP->ResolveIndirectFunction(this, error); + { + code_addr = processSP->ResolveIndirectFunction(this, error); + if (!error.Success()) + code_addr = LLDB_INVALID_ADDRESS; + } } - - addr_t code_addr = GetLoadAddress (target); - + else + { + code_addr = GetLoadAddress (target); + } + + if (code_addr == LLDB_INVALID_ADDRESS) + return code_addr; + if (target) return target->GetCallableLoadAddress (code_addr, GetAddressClass()); return code_addr; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index f71b9cac3a33..43f6ce9e6a13 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -1596,14 +1596,6 @@ DynamicLoaderMacOSXDYLD::PrivateProcessStateChanged (Process *process, StateType } } -// This bit in the n_desc field of the mach file means that this is a -// stub that runs arbitrary code to determine the trampoline target. -// We've established a naming convention with the CoreOS folks for the -// equivalent symbols they will use for this (which the objc guys didn't follow...) -// For now we'll just look for all symbols matching that naming convention... - -#define MACH_O_N_SYMBOL_RESOLVER 0x100 - ThreadPlanSP DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) { @@ -1612,104 +1604,123 @@ DynamicLoaderMacOSXDYLD::GetStepThroughTrampolinePlan (Thread &thread, bool stop const SymbolContext ¤t_context = current_frame->GetSymbolContext(eSymbolContextSymbol); Symbol *current_symbol = current_context.symbol; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + TargetSP target_sp (thread.CalculateTarget()); if (current_symbol != NULL) { + std::vector<Address> addresses; + if (current_symbol->IsTrampoline()) { const ConstString &trampoline_name = current_symbol->GetMangled().GetName(Mangled::ePreferMangled); if (trampoline_name) { - SymbolContextList target_symbols; - TargetSP target_sp (thread.CalculateTarget()); const ModuleList &images = target_sp->GetImages(); - images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, target_symbols); - - size_t num_original_symbols = target_symbols.GetSize(); - // FIXME: The resolver symbol is only valid in object files. In binaries it is reused for the - // shared library slot number. So we'll have to look this up in the dyld info. - // For now, just turn this off. + SymbolContextList code_symbols; + images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeCode, code_symbols); + size_t num_code_symbols = code_symbols.GetSize(); - // bool orig_is_resolver = (current_symbol->GetFlags() & MACH_O_N_SYMBOL_RESOLVER) == MACH_O_N_SYMBOL_RESOLVER; - // FIXME: Actually that isn't true, the N_SYMBOL_RESOLVER bit is only valid in .o files. You can't use - // the symbol flags to tell whether something is a symbol resolver in a linked image. - bool orig_is_resolver = false; - - if (num_original_symbols > 0) + if (num_code_symbols > 0) { - // We found symbols that look like they are the targets to our symbol. Now look through the - // modules containing our symbols to see if there are any for our symbol. - - ModuleList modules_to_search; - - for (size_t i = 0; i < num_original_symbols; i++) + for (uint32_t i = 0; i < num_code_symbols; i++) { - SymbolContext sc; - target_symbols.GetContextAtIndex(i, sc); - - ModuleSP module_sp (sc.symbol->CalculateSymbolContextModule()); - if (module_sp) - modules_to_search.AppendIfNeeded(module_sp); - } - - // If the original stub symbol is a resolver, then we don't want to break on the symbol with the - // original name, but instead on all the symbols it could resolve to since otherwise we would stop - // in the middle of the resolution... - // Note that the stub is not of the resolver type it will point to the equivalent symbol, - // not the original name, so in that case we don't need to do anything. - - if (orig_is_resolver) - { - target_symbols.Clear(); - - FindEquivalentSymbols (current_symbol, modules_to_search, target_symbols); - } - - // FIXME - Make the Run to Address take multiple addresses, and - // run to any of them. - uint32_t num_symbols = target_symbols.GetSize(); - if (num_symbols > 0) - { - std::vector<lldb::addr_t> addresses; - addresses.resize (num_symbols); - for (uint32_t i = 0; i < num_symbols; i++) + SymbolContext context; + AddressRange addr_range; + if (code_symbols.GetContextAtIndex(i, context)) { - SymbolContext context; - AddressRange addr_range; - if (target_symbols.GetContextAtIndex(i, context)) + context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range); + addresses.push_back(addr_range.GetBaseAddress()); + if (log) { - context.GetAddressRange (eSymbolContextEverything, 0, false, addr_range); - lldb::addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get()); - addresses[i] = load_addr; + addr_t load_addr = addr_range.GetBaseAddress().GetLoadAddress(target_sp.get()); + + log->Printf ("Found a trampoline target symbol at 0x%" PRIx64 ".", load_addr); } } - if (addresses.size() > 0) - thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, addresses, stop_others)); - else + } + } + + SymbolContextList reexported_symbols; + images.FindSymbolsWithNameAndType(trampoline_name, eSymbolTypeReExported, reexported_symbols); + size_t num_reexported_symbols = reexported_symbols.GetSize(); + if (num_reexported_symbols > 0) + { + for (uint32_t i = 0; i < num_reexported_symbols; i++) + { + SymbolContext context; + if (reexported_symbols.GetContextAtIndex(i, context)) { - if (log) - log->Printf ("Couldn't resolve the symbol contexts."); + if (context.symbol) + { + Symbol *actual_symbol = context.symbol->ResolveReExportedSymbol(*target_sp.get()); + if (actual_symbol) + { + if (actual_symbol->GetAddress().IsValid()) + { + addresses.push_back(actual_symbol->GetAddress()); + if (log) + { + lldb::addr_t load_addr = actual_symbol->GetAddress().GetLoadAddress(target_sp.get()); + log->Printf ("Found a re-exported symbol: %s at 0x%" PRIx64 ".", + actual_symbol->GetName().GetCString(), load_addr); + } + } + } + } } } - else + } + } + } + else if (current_symbol->GetType() == eSymbolTypeReExported) + { + // I am not sure we could ever end up stopped AT a re-exported symbol. But just in case: + + const Symbol *actual_symbol = current_symbol->ResolveReExportedSymbol(*(target_sp.get())); + if (actual_symbol) + { + Address target_addr(actual_symbol->GetAddress()); + if (target_addr.IsValid()) + { + if (log) + log->Printf ("Found a re-exported symbol: %s pointing to: %s at 0x%" PRIx64 ".", + current_symbol->GetName().GetCString(), + actual_symbol->GetName().GetCString(), + target_addr.GetLoadAddress(target_sp.get())); + addresses.push_back (target_addr.GetLoadAddress(target_sp.get())); + + } + } + } + + if (addresses.size() > 0) + { + // First check whether any of the addresses point to Indirect symbols, and if they do, resolve them: + std::vector<lldb::addr_t> load_addrs; + for (Address address : addresses) + { + Symbol *symbol = address.CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) + { + Error error; + addr_t resolved_addr = thread.GetProcess()->ResolveIndirectFunction(&symbol->GetAddress(), error); + if (error.Success()) { + load_addrs.push_back(resolved_addr); if (log) - { - log->Printf ("Found a resolver stub for: \"%s\" but could not find any symbols it resolves to.", - trampoline_name.AsCString()); - } + log->Printf("ResolveIndirectFunction found resolved target for %s at 0x%" PRIx64 ".", + symbol->GetName().GetCString(), resolved_addr); } } else { - if (log) - { - log->Printf ("Could not find symbol for trampoline target: \"%s\"", trampoline_name.AsCString()); - } + load_addrs.push_back(address.GetLoadAddress(target_sp.get())); } + } + thread_plan_sp.reset (new ThreadPlanRunToAddress (thread, load_addrs, stop_others)); } } else @@ -1732,7 +1743,7 @@ DynamicLoaderMacOSXDYLD::FindEquivalentSymbols (lldb_private::Symbol *original_s size_t initial_size = equivalent_symbols.GetSize(); - static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Z0-9]+)$"; + static const char *resolver_name_regex = "(_gc|_non_gc|\\$[A-Za-z0-9\\$]+)$"; std::string equivalent_regex_buf("^"); equivalent_regex_buf.append (trampoline_name.GetCString()); equivalent_regex_buf.append (resolver_name_regex); diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 878f15645ec1..9781dcb093ac 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -403,7 +403,9 @@ ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp, FileSpecList filter_modules; BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions); SearchFilterSP filter_sp (CreateExceptionSearchFilter ()); - return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, false); + const bool hardware = false; + const bool resolve_indirect_functions = false; + return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, hardware, resolve_indirect_functions); } void diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index a5bd9b510a41..62394623c59d 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -632,20 +632,6 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) return error; } -addr_t -ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error) -{ - addr_t function_addr = LLDB_INVALID_ADDRESS; - if (address == NULL) { - error.SetErrorStringWithFormat("unable to determine direct function call for NULL address"); - } else if (!InferiorCall(this, address, function_addr)) { - function_addr = LLDB_INVALID_ADDRESS; - error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s", - address->CalculateSymbolContextSymbol()->GetName().AsCString()); - } - return function_addr; -} - size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h index beacb0186c65..7f705d33fe68 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -104,9 +104,6 @@ public: virtual lldb_private::Error DoDeallocateMemory(lldb::addr_t ptr); - virtual lldb::addr_t - ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error); - virtual size_t GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 6d1b04f7f1a7..1d5d19fad25f 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -34,9 +34,16 @@ using namespace lldb; using namespace lldb_private; -bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, - addr_t addr, addr_t length, unsigned prot, - unsigned flags, addr_t fd, addr_t offset) { +bool +lldb_private::InferiorCallMmap (Process *process, + addr_t &allocated_addr, + addr_t addr, + addr_t length, + unsigned prot, + unsigned flags, + addr_t fd, + addr_t offset) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL) return false; @@ -139,8 +146,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, return false; } -bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, - addr_t length) { +bool +lldb_private::InferiorCallMunmap (Process *process, + addr_t addr, + addr_t length) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL) return false; @@ -209,7 +219,14 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, return false; } -bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { +// FIXME: This has nothing to do with Posix, it is just a convenience function that calls a +// function of the form "void * (*)(void)". We should find a better place to put this. + +bool +lldb_private::InferiorCall (Process *process, + const Address *address, + addr_t &returned_func) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL || address == NULL) return false; @@ -233,7 +250,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { - StreamFile error_strm; + StreamString error_strm; // This plan is a utility plan, so set it to discard itself when done. call_plan_sp->SetIsMasterPlan (true); call_plan_sp->SetOkayToDiscard(true); diff --git a/lldb/source/Target/LanguageRuntime.cpp b/lldb/source/Target/LanguageRuntime.cpp index 2fdc2539d08b..a2b7f1d6ae85 100644 --- a/lldb/source/Target/LanguageRuntime.cpp +++ b/lldb/source/Target/LanguageRuntime.cpp @@ -269,7 +269,8 @@ LanguageRuntime::CreateExceptionBreakpoint (Target &target, BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language)); bool hardware = false; - BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware)); + bool resolve_indirect_functions = false; + BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions)); if (is_internal) exc_breakpt_sp->SetBreakpointKind("exception"); diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 8b1aba634b77..a5ef629e5eb2 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/InputReader.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Expression/ClangUserExpression.h" @@ -41,6 +42,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanBase.h" +#include "Plugins/Process/Utility/InferiorCallPOSIX.h" #ifndef LLDB_DISABLE_POSIX #include <spawn.h> @@ -1052,6 +1054,7 @@ Process::Process(Target &target, Listener &listener) : m_currently_handling_event(false), m_finalize_called(false), m_clear_thread_plans_on_stop (false), + m_force_next_event_delivery(false), m_last_broadcast_state (eStateInvalid), m_destroy_in_process (false), m_can_jit(eCanJITDontKnow) @@ -2143,7 +2146,60 @@ Process::EnableBreakpointSiteByID (lldb::user_id_t break_id) lldb::break_id_t Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware) { - const addr_t load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); + addr_t load_addr = LLDB_INVALID_ADDRESS; + + bool show_error = true; + switch (GetState()) + { + case eStateInvalid: + case eStateUnloaded: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateDetached: + case eStateExited: + show_error = false; + break; + + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + show_error = IsAlive(); + break; + } + + // Reset the IsIndirect flag here, in case the location changes from + // pointing to a indirect symbol to a regular symbol. + owner->SetIsIndirect (false); + + if (owner->ShouldResolveIndirectFunctions()) + { + Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) + { + Error error; + load_addr = ResolveIndirectFunction (&symbol->GetAddress(), error); + if (!error.Success() && show_error) + { + m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", + symbol->GetAddress().GetLoadAddress(&m_target), + owner->GetBreakpoint().GetID(), + owner->GetID(), + error.AsCString() ? error.AsCString() : "unkown error"); + return LLDB_INVALID_BREAK_ID; + } + Address resolved_address(load_addr); + load_addr = resolved_address.GetOpcodeLoadAddress (&m_target); + owner->SetIsIndirect(true); + } + else + load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); + } + else + load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); + if (load_addr != LLDB_INVALID_ADDRESS) { BreakpointSiteSP bp_site_sp; @@ -2172,28 +2228,6 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw } else { - bool show_error = true; - switch (GetState()) - { - case eStateInvalid: - case eStateUnloaded: - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateDetached: - case eStateExited: - show_error = false; - break; - - case eStateStopped: - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - show_error = IsAlive(); - break; - } - if (show_error) { // Report error for setting breakpoint... @@ -3804,33 +3838,38 @@ Process::ShouldBroadcastEvent (Event *event_ptr) // stopped -> running: Report except when there is one or more no votes // and no yes votes. SynchronouslyNotifyStateChanged (state); - switch (m_last_broadcast_state) + if (m_force_next_event_delivery) + return_value = true; + else { - case eStateRunning: - case eStateStepping: - // We always suppress multiple runnings with no PUBLIC stop in between. - return_value = false; - break; - default: - // TODO: make this work correctly. For now always report - // run if we aren't running so we don't miss any runnning - // events. If I run the lldb/test/thread/a.out file and - // break at main.cpp:58, run and hit the breakpoints on - // multiple threads, then somehow during the stepping over - // of all breakpoints no run gets reported. + switch (m_last_broadcast_state) + { + case eStateRunning: + case eStateStepping: + // We always suppress multiple runnings with no PUBLIC stop in between. + return_value = false; + break; + default: + // TODO: make this work correctly. For now always report + // run if we aren't running so we don't miss any runnning + // events. If I run the lldb/test/thread/a.out file and + // break at main.cpp:58, run and hit the breakpoints on + // multiple threads, then somehow during the stepping over + // of all breakpoints no run gets reported. - // This is a transition from stop to run. - switch (m_thread_list.ShouldReportRun (event_ptr)) - { - case eVoteYes: - case eVoteNoOpinion: - return_value = true; - break; - case eVoteNo: - return_value = false; - break; - } - break; + // This is a transition from stop to run. + switch (m_thread_list.ShouldReportRun (event_ptr)) + { + case eVoteYes: + case eVoteNoOpinion: + return_value = true; + break; + case eVoteNo: + return_value = false; + break; + } + break; + } } break; case eStateStopped: @@ -3903,6 +3942,9 @@ Process::ShouldBroadcastEvent (Event *event_ptr) break; } + // Forcing the next event delivery is a one shot deal. So reset it here. + m_force_next_event_delivery = false; + // We do some coalescing of events (for instance two consecutive running events get coalesced.) // But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state // to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done, @@ -4984,6 +5026,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, final_timeout.OffsetWithMicroSeconds(timeout_usec); } + // This isn't going to work if there are unfetched events on the queue. + // Are there cases where we might want to run the remaining events here, and then try to + // call the function? That's probably being too tricky for our own good. + + Event *other_events = listener.PeekAtNextEvent(); + if (other_events != NULL) + { + errors.Printf("Calling RunThreadPlan with pending events on the queue."); + return eExecutionSetupError; + } + + // We also need to make sure that the next event is delivered. We might be calling a function as part of + // a thread plan, in which case the last delivered event could be the running event, and we don't want + // event coalescing to cause us to lose OUR running event... + ForceNextEventDelivery(); + // This while loop must exit out the bottom, there's cleanup that we need to do when we are done. // So don't call return anywhere within it. @@ -5772,3 +5830,39 @@ Process::DidExec () target.DidExec(); } +addr_t +Process::ResolveIndirectFunction(const Address *address, Error &error) +{ + if (address == nullptr) + { + Symbol *symbol = address->CalculateSymbolContextSymbol(); + error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s", + symbol ? symbol->GetName().AsCString() : "<UNKNOWN>"); + return LLDB_INVALID_ADDRESS; + } + + addr_t function_addr = LLDB_INVALID_ADDRESS; + + addr_t addr = address->GetLoadAddress(&GetTarget()); + std::map<addr_t,addr_t>::const_iterator iter = m_resolved_indirect_addresses.find(addr); + if (iter != m_resolved_indirect_addresses.end()) + { + function_addr = (*iter).second; + } + else + { + if (!InferiorCall(this, address, function_addr)) + { + Symbol *symbol = address->CalculateSymbolContextSymbol(); + error.SetErrorStringWithFormat ("Unable to call resolver for indirect function %s", + symbol ? symbol->GetName().AsCString() : "<UNKNOWN>"); + function_addr = LLDB_INVALID_ADDRESS; + } + else + { + m_resolved_indirect_addresses.insert(std::pair<addr_t, addr_t>(addr, function_addr)); + } + } + return function_addr; +} + diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index a0435d137fb7..a34d53e88f8d 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -250,7 +250,7 @@ Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules, { SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list)); BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } @@ -304,7 +304,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, line_no, check_inlines, skip_prologue)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } @@ -331,7 +331,7 @@ Target::CreateBreakpoint (Address &addr, bool internal, bool hardware) { SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this())); BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false); } BreakpointSP @@ -356,7 +356,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, func_name_type_mask, Breakpoint::Exact, skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } return bp_sp; } @@ -383,7 +383,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, func_names, func_name_type_mask, skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } return bp_sp; } @@ -411,7 +411,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, num_names, func_name_type_mask, skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } return bp_sp; } @@ -489,7 +489,7 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules, func_regex, skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } lldb::BreakpointSP @@ -499,12 +499,12 @@ Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_ } BreakpointSP -Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware) +Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols) { BreakpointSP bp_sp; if (filter_sp && resolver_sp) { - bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware)); + bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware, resolve_indirect_symbols)); resolver_sp->SetBreakpoint (bp_sp.get()); if (internal)