| //===-- BreakpointResolverAddress.cpp -------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lldb/Breakpoint/BreakpointResolverAddress.h" | |
| #include "lldb/Breakpoint/BreakpointLocation.h" | |
| #include "lldb/Core/Module.h" | |
| #include "lldb/Core/Section.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Target/Target.h" | |
| #include "lldb/Utility/LLDBLog.h" | |
| #include "lldb/Utility/StreamString.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| // BreakpointResolverAddress: | |
| BreakpointResolverAddress::BreakpointResolverAddress( | |
| const BreakpointSP &bkpt, const Address &addr, const FileSpec &module_spec) | |
| : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver), | |
| m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), | |
| m_module_filespec(module_spec) {} | |
| BreakpointResolverAddress::BreakpointResolverAddress(const BreakpointSP &bkpt, | |
| const Address &addr) | |
| : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver), | |
| m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS) {} | |
| BreakpointResolverSP BreakpointResolverAddress::CreateFromStructuredData( | |
| const StructuredData::Dictionary &options_dict, Status &error) { | |
| llvm::StringRef module_name; | |
| lldb::offset_t addr_offset; | |
| FileSpec module_filespec; | |
| bool success; | |
| success = options_dict.GetValueForKeyAsInteger( | |
| GetKey(OptionNames::AddressOffset), addr_offset); | |
| if (!success) { | |
| error = Status::FromErrorString( | |
| "BRFL::CFSD: Couldn't find address offset entry."); | |
| return nullptr; | |
| } | |
| Address address(addr_offset); | |
| success = options_dict.HasKey(GetKey(OptionNames::ModuleName)); | |
| if (success) { | |
| success = options_dict.GetValueForKeyAsString( | |
| GetKey(OptionNames::ModuleName), module_name); | |
| if (!success) { | |
| error = Status::FromErrorString( | |
| "BRA::CFSD: Couldn't read module name entry."); | |
| return nullptr; | |
| } | |
| module_filespec.SetFile(module_name, FileSpec::Style::native); | |
| } | |
| return std::make_shared<BreakpointResolverAddress>(nullptr, address, | |
| module_filespec); | |
| } | |
| StructuredData::ObjectSP | |
| BreakpointResolverAddress::SerializeToStructuredData() { | |
| StructuredData::DictionarySP options_dict_sp( | |
| new StructuredData::Dictionary()); | |
| SectionSP section_sp = m_addr.GetSection(); | |
| if (section_sp) { | |
| if (ModuleSP module_sp = section_sp->GetModule()) { | |
| const FileSpec &module_fspec = module_sp->GetFileSpec(); | |
| options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName), | |
| module_fspec.GetPath().c_str()); | |
| } | |
| options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset), | |
| m_addr.GetOffset()); | |
| } else { | |
| options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset), | |
| m_addr.GetOffset()); | |
| if (m_module_filespec) { | |
| options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName), | |
| m_module_filespec.GetPath()); | |
| } | |
| } | |
| return WrapOptionsDict(options_dict_sp); | |
| } | |
| void BreakpointResolverAddress::ResolveBreakpoint(SearchFilter &filter) { | |
| // If the address is not section relative, then we should not try to re- | |
| // resolve it, it is just some random address and we wouldn't know what to do | |
| // on reload. But if it is section relative, we need to re-resolve it since | |
| // the section it's in may have shifted on re-run. | |
| bool re_resolve = false; | |
| if (m_addr.GetSection() || m_module_filespec) | |
| re_resolve = true; | |
| else if (GetBreakpoint()->GetNumLocations() == 0) | |
| re_resolve = true; | |
| if (re_resolve) | |
| BreakpointResolver::ResolveBreakpoint(filter); | |
| } | |
| void BreakpointResolverAddress::ResolveBreakpointInModules( | |
| SearchFilter &filter, ModuleList &modules) { | |
| // See comment in ResolveBreakpoint. | |
| bool re_resolve = false; | |
| if (m_addr.GetSection()) | |
| re_resolve = true; | |
| else if (GetBreakpoint()->GetNumLocations() == 0) | |
| re_resolve = true; | |
| if (re_resolve) | |
| BreakpointResolver::ResolveBreakpointInModules(filter, modules); | |
| } | |
| Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback( | |
| SearchFilter &filter, SymbolContext &context, Address *addr) { | |
| Log *log = GetLog(LLDBLog::Breakpoints); | |
| BreakpointSP breakpoint_sp = GetBreakpoint(); | |
| Breakpoint &breakpoint = *breakpoint_sp; | |
| if (filter.AddressPasses(m_addr)) { | |
| if (breakpoint.GetNumLocations() == 0) { | |
| // If the address is just an offset, and we're given a module, see if we | |
| // can find the appropriate module loaded in the binary, and fix up | |
| // m_addr to use that. | |
| if (!m_addr.IsSectionOffset() && m_module_filespec) { | |
| Target &target = breakpoint.GetTarget(); | |
| ModuleSpec module_spec(m_module_filespec); | |
| ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec); | |
| if (module_sp) { | |
| Address tmp_address; | |
| if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address)) | |
| m_addr = tmp_address; | |
| else | |
| return Searcher::eCallbackReturnStop; | |
| } else { | |
| // If we didn't find the module, then we can't resolve the address. | |
| return Searcher::eCallbackReturnStop; | |
| } | |
| } | |
| m_resolved_addr = m_addr.GetLoadAddress(&breakpoint.GetTarget()); | |
| BreakpointLocationSP bp_loc_sp(AddLocation(m_addr)); | |
| if (bp_loc_sp && !breakpoint.IsInternal()) { | |
| StreamString s; | |
| bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); | |
| LLDB_LOGF(log, "Added location: %s\n", s.GetData()); | |
| } | |
| } else { | |
| BreakpointLocationSP loc_sp = breakpoint.GetLocationAtIndex(0); | |
| lldb::addr_t cur_load_location = | |
| m_addr.GetLoadAddress(&breakpoint.GetTarget()); | |
| if (cur_load_location != m_resolved_addr) { | |
| m_resolved_addr = cur_load_location; | |
| if (llvm::Error error = loc_sp->ClearBreakpointSite()) | |
| LLDB_LOG_ERROR(log, std::move(error), "{0}"); | |
| if (llvm::Error error = loc_sp->ResolveBreakpointSite()) | |
| LLDB_LOG_ERROR(log, std::move(error), "{0}"); | |
| } | |
| } | |
| } | |
| return Searcher::eCallbackReturnStop; | |
| } | |
| lldb::SearchDepth BreakpointResolverAddress::GetDepth() { | |
| return lldb::eSearchDepthTarget; | |
| } | |
| void BreakpointResolverAddress::GetDescription(Stream *s) { | |
| s->PutCString("address = "); | |
| m_addr.Dump(s, GetBreakpoint()->GetTarget().GetProcessSP().get(), | |
| Address::DumpStyleModuleWithFileAddress, | |
| Address::DumpStyleLoadAddress); | |
| } | |
| void BreakpointResolverAddress::Dump(Stream *s) const {} | |
| lldb::BreakpointResolverSP | |
| BreakpointResolverAddress::CopyForBreakpoint(BreakpointSP &breakpoint) { | |
| lldb::BreakpointResolverSP ret_sp( | |
| new BreakpointResolverAddress(breakpoint, m_addr)); | |
| return ret_sp; | |
| } |