text: //===-- BreakpointResolverAddress.cpp ---------------------------*- C++ -*-===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  
  #include "lldb/Breakpoint/BreakpointResolverAddress.h"
  
  // C Includes
  // C++ Includes
  // Other libraries and framework includes
  // Project includes
  
  #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/Log.h"
  #include "lldb/Utility/StreamString.h"
  
  using namespace lldb;
  using namespace lldb_private;
  
  //----------------------------------------------------------------------
  // BreakpointResolverAddress:
  //----------------------------------------------------------------------
  BreakpointResolverAddress::BreakpointResolverAddress(
      Breakpoint *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(Breakpoint *bkpt,
                                                       const Address &addr)
      : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
        m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), m_module_filespec() {
  }
  
  BreakpointResolverAddress::~BreakpointResolverAddress() {}
  
  BreakpointResolver *BreakpointResolverAddress::CreateFromStructuredData(
      Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
      Status &error) {
    llvm::StringRef module_name;
    lldb::addr_t addr_offset;
    FileSpec module_filespec;
    bool success;
  
    success = options_dict.GetValueForKeyAsInteger(
        GetKey(OptionNames::AddressOffset), addr_offset);
    if (!success) {
      error.SetErrorString("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.SetErrorString("BRA::CFSD: Couldn't read module name entry.");
        return nullptr;
      }
      module_filespec.SetFile(module_name, false, FileSpec::Style::native);
    }
    return new BreakpointResolverAddress(bkpt, address, module_filespec);
  }
  
  StructuredData::ObjectSP
  BreakpointResolverAddress::SerializeToStructuredData() {
    StructuredData::DictionarySP options_dict_sp(
        new StructuredData::Dictionary());
    SectionSP section_sp = m_addr.GetSection();
    if (section_sp) {
      ModuleSP module_sp = section_sp->GetModule();
      ConstString module_name;
      if (module_sp)
        module_name.SetCString(module_name.GetCString());
  
      options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
                                     module_name.GetCString());
      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);
    return StructuredData::ObjectSP();
  }
  
  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 (m_breakpoint->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 (m_breakpoint->GetNumLocations() == 0)
      re_resolve = true;
  
    if (re_resolve)
      BreakpointResolver::ResolveBreakpointInModules(filter, modules);
  }
  
  Searcher::CallbackReturn
  BreakpointResolverAddress::SearchCallback(SearchFilter &filter,
                                            SymbolContext &context, Address *addr,
                                            bool containing) {
    assert(m_breakpoint != NULL);
  
    if (filter.AddressPasses(m_addr)) {
      if (m_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 = m_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;
          }
        }
  
        m_resolved_addr = m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
        BreakpointLocationSP bp_loc_sp(AddLocation(m_addr));
        if (bp_loc_sp && !m_breakpoint->IsInternal()) {
          StreamString s;
          bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
          Log *log(
              lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
          if (log)
            log->Printf("Added location: %s\n", s.GetData());
        }
      } else {
        BreakpointLocationSP loc_sp = m_breakpoint->GetLocationAtIndex(0);
        lldb::addr_t cur_load_location =
            m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
        if (cur_load_location != m_resolved_addr) {
          m_resolved_addr = cur_load_location;
          loc_sp->ClearBreakpointSite();
          loc_sp->ResolveBreakpointSite();
        }
      }
    }
    return Searcher::eCallbackReturnStop;
  }
  
  Searcher::Depth BreakpointResolverAddress::GetDepth() {
    return Searcher::eDepthTarget;
  }
  
  void BreakpointResolverAddress::GetDescription(Stream *s) {
    s->PutCString("address = ");
    m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(),
                Address::DumpStyleModuleWithFileAddress,
                Address::DumpStyleLoadAddress);
  }
  
  void BreakpointResolverAddress::Dump(Stream *s) const {}
  
  lldb::BreakpointResolverSP
  BreakpointResolverAddress::CopyForBreakpoint(Breakpoint &breakpoint) {
    lldb::BreakpointResolverSP ret_sp(
        new BreakpointResolverAddress(&breakpoint, m_addr));
    return ret_sp;
  }
  