180814287SRaphael Isemann //===-- SectionLoadList.cpp -----------------------------------------------===//
217f69208SGreg Clayton //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
617f69208SGreg Clayton //
717f69208SGreg Clayton //===----------------------------------------------------------------------===//
817f69208SGreg Clayton 
917f69208SGreg Clayton #include "lldb/Target/SectionLoadList.h"
1017f69208SGreg Clayton 
1117f69208SGreg Clayton #include "lldb/Core/Module.h"
1217f69208SGreg Clayton #include "lldb/Core/Section.h"
1317f69208SGreg Clayton #include "lldb/Symbol/Block.h"
1417f69208SGreg Clayton #include "lldb/Symbol/Symbol.h"
1517f69208SGreg Clayton #include "lldb/Symbol/SymbolContext.h"
16*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
176f9e6901SZachary Turner #include "lldb/Utility/Log.h"
18bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
1917f69208SGreg Clayton 
2017f69208SGreg Clayton using namespace lldb;
2117f69208SGreg Clayton using namespace lldb_private;
2217f69208SGreg Clayton 
SectionLoadList(const SectionLoadList & rhs)23b9c1b51eSKate Stone SectionLoadList::SectionLoadList(const SectionLoadList &rhs)
24b9c1b51eSKate Stone     : m_addr_to_sect(), m_sect_to_addr(), m_mutex() {
2516ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(rhs.m_mutex);
26d5944cd1SGreg Clayton   m_addr_to_sect = rhs.m_addr_to_sect;
27d5944cd1SGreg Clayton   m_sect_to_addr = rhs.m_sect_to_addr;
28d5944cd1SGreg Clayton }
29d5944cd1SGreg Clayton 
operator =(const SectionLoadList & rhs)30b9c1b51eSKate Stone void SectionLoadList::operator=(const SectionLoadList &rhs) {
31cdd4892fSJim Ingham   std::lock(m_mutex, rhs.m_mutex);
32cdd4892fSJim Ingham   std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex, std::adopt_lock);
33cdd4892fSJim Ingham   std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex, std::adopt_lock);
34d5944cd1SGreg Clayton   m_addr_to_sect = rhs.m_addr_to_sect;
35d5944cd1SGreg Clayton   m_sect_to_addr = rhs.m_sect_to_addr;
36d5944cd1SGreg Clayton }
37d5944cd1SGreg Clayton 
IsEmpty() const38b9c1b51eSKate Stone bool SectionLoadList::IsEmpty() const {
3916ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
406d093451SGreg Clayton   return m_addr_to_sect.empty();
4117f69208SGreg Clayton }
4217f69208SGreg Clayton 
Clear()43b9c1b51eSKate Stone void SectionLoadList::Clear() {
4416ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
456d093451SGreg Clayton   m_addr_to_sect.clear();
466d093451SGreg Clayton   m_sect_to_addr.clear();
4717f69208SGreg Clayton }
4817f69208SGreg Clayton 
4917f69208SGreg Clayton addr_t
GetSectionLoadAddress(const lldb::SectionSP & section) const50b9c1b51eSKate Stone SectionLoadList::GetSectionLoadAddress(const lldb::SectionSP &section) const {
5117f69208SGreg Clayton   // TODO: add support for the same section having multiple load addresses
5217f69208SGreg Clayton   addr_t section_load_addr = LLDB_INVALID_ADDRESS;
53b9c1b51eSKate Stone   if (section) {
5416ff8604SSaleem Abdulrasool     std::lock_guard<std::recursive_mutex> guard(m_mutex);
55b9c1b51eSKate Stone     sect_to_addr_collection::const_iterator pos =
56b9c1b51eSKate Stone         m_sect_to_addr.find(section.get());
576d093451SGreg Clayton 
586d093451SGreg Clayton     if (pos != m_sect_to_addr.end())
596d093451SGreg Clayton       section_load_addr = pos->second;
6010177aa0SGreg Clayton   }
6117f69208SGreg Clayton   return section_load_addr;
6217f69208SGreg Clayton }
6317f69208SGreg Clayton 
SetSectionLoadAddress(const lldb::SectionSP & section,addr_t load_addr,bool warn_multiple)64b9c1b51eSKate Stone bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP &section,
65b9c1b51eSKate Stone                                             addr_t load_addr,
66b9c1b51eSKate Stone                                             bool warn_multiple) {
67a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::DynamicLoader);
68fd814c5aSGreg Clayton   ModuleSP module_sp(section->GetModule());
69fd814c5aSGreg Clayton 
70b9c1b51eSKate Stone   if (module_sp) {
713b7e1981SPavel Labath     LLDB_LOGV(log, "(section = {0} ({1}.{2}), load_addr = {3:x}) module = {4}",
723b7e1981SPavel Labath               section.get(), module_sp->GetFileSpec(), section->GetName(),
733b7e1981SPavel Labath               load_addr, module_sp.get());
7417f69208SGreg Clayton 
75c859e2d5SGreg Clayton     if (section->GetByteSize() == 0)
76c859e2d5SGreg Clayton       return false; // No change
77c859e2d5SGreg Clayton 
781e8ac36bSGreg Clayton     // Fill in the section -> load_addr map
7916ff8604SSaleem Abdulrasool     std::lock_guard<std::recursive_mutex> guard(m_mutex);
80b9c1b51eSKate Stone     sect_to_addr_collection::iterator sta_pos =
81b9c1b51eSKate Stone         m_sect_to_addr.find(section.get());
82b9c1b51eSKate Stone     if (sta_pos != m_sect_to_addr.end()) {
836d093451SGreg Clayton       if (load_addr == sta_pos->second)
8410177aa0SGreg Clayton         return false; // No change...
8510177aa0SGreg Clayton       else
866d093451SGreg Clayton         sta_pos->second = load_addr;
87b9c1b51eSKate Stone     } else
887820bd1eSGreg Clayton       m_sect_to_addr[section.get()] = load_addr;
896d093451SGreg Clayton 
901e8ac36bSGreg Clayton     // Fill in the load_addr -> section map
916d093451SGreg Clayton     addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
92b9c1b51eSKate Stone     if (ats_pos != m_addr_to_sect.end()) {
931e8ac36bSGreg Clayton       // Some sections are ok to overlap, and for others we should warn. When
941e8ac36bSGreg Clayton       // we have multiple load addresses that correspond to a section, we will
95aaa0ba31SBruce Mitchener       // always attribute the section to the be last section that claims it
961e8ac36bSGreg Clayton       // exists at that address. Sometimes it is ok for more that one section
9705097246SAdrian Prantl       // to be loaded at a specific load address, and other times it isn't. The
9805097246SAdrian Prantl       // "warn_multiple" parameter tells us if we should warn in this case or
9905097246SAdrian Prantl       // not. The DynamicLoader plug-in subclasses should know which sections
10005097246SAdrian Prantl       // should warn and which shouldn't (darwin shared cache modules all
10105097246SAdrian Prantl       // shared the same "__LINKEDIT" sections, so the dynamic loader can pass
10205097246SAdrian Prantl       // false for "warn_multiple").
103b9c1b51eSKate Stone       if (warn_multiple && section != ats_pos->second) {
104e72dfb32SGreg Clayton         ModuleSP module_sp(section->GetModule());
105b9c1b51eSKate Stone         if (module_sp) {
1069d192e1aSGreg Clayton           ModuleSP curr_module_sp(ats_pos->second->GetModule());
107b9c1b51eSKate Stone           if (curr_module_sp) {
108b9c1b51eSKate Stone             module_sp->ReportWarning(
109b9c1b51eSKate Stone                 "address 0x%16.16" PRIx64
110b9c1b51eSKate Stone                 " maps to more than one section: %s.%s and %s.%s",
111b9c1b51eSKate Stone                 load_addr, module_sp->GetFileSpec().GetFilename().GetCString(),
112c859e2d5SGreg Clayton                 section->GetName().GetCString(),
1139d192e1aSGreg Clayton                 curr_module_sp->GetFileSpec().GetFilename().GetCString(),
114c859e2d5SGreg Clayton                 ats_pos->second->GetName().GetCString());
115c859e2d5SGreg Clayton           }
116c859e2d5SGreg Clayton         }
1179d192e1aSGreg Clayton       }
1186d093451SGreg Clayton       ats_pos->second = section;
119b9c1b51eSKate Stone     } else
1206d093451SGreg Clayton       m_addr_to_sect[load_addr] = section;
12117f69208SGreg Clayton     return true; // Changed
122fd814c5aSGreg Clayton 
123b9c1b51eSKate Stone   } else {
124b9c1b51eSKate Stone     if (log) {
12563e5fb76SJonas Devlieghere       LLDB_LOGF(
12663e5fb76SJonas Devlieghere           log,
127b9c1b51eSKate Stone           "SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64
128b9c1b51eSKate Stone           ") error: module has been deleted",
129324a1036SSaleem Abdulrasool           __FUNCTION__, static_cast<void *>(section.get()),
130b9c1b51eSKate Stone           section->GetName().AsCString(), load_addr);
131fd814c5aSGreg Clayton     }
132fd814c5aSGreg Clayton   }
133fd814c5aSGreg Clayton   return false;
13417f69208SGreg Clayton }
13517f69208SGreg Clayton 
SetSectionUnloaded(const lldb::SectionSP & section_sp)136b9c1b51eSKate Stone size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp) {
1377820bd1eSGreg Clayton   size_t unload_count = 0;
1387820bd1eSGreg Clayton 
139b9c1b51eSKate Stone   if (section_sp) {
140a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::DynamicLoader);
14117f69208SGreg Clayton 
1423b7e1981SPavel Labath     if (log && log->GetVerbose()) {
143cbff63adSJim Ingham       ModuleSP module_sp = section_sp->GetModule();
144cbff63adSJim Ingham       std::string module_name("<Unknown>");
145b9c1b51eSKate Stone       if (module_sp) {
146b9c1b51eSKate Stone         const FileSpec &module_file_spec(
147b9c1b51eSKate Stone             section_sp->GetModule()->GetFileSpec());
148cbff63adSJim Ingham         module_name = module_file_spec.GetPath();
149cbff63adSJim Ingham       }
15063e5fb76SJonas Devlieghere       LLDB_LOGF(log, "SectionLoadList::%s (section = %p (%s.%s))", __FUNCTION__,
151b9c1b51eSKate Stone                 static_cast<void *>(section_sp.get()), module_name.c_str(),
1527820bd1eSGreg Clayton                 section_sp->GetName().AsCString());
1538b2fe6dcSGreg Clayton     }
15417f69208SGreg Clayton 
15516ff8604SSaleem Abdulrasool     std::lock_guard<std::recursive_mutex> guard(m_mutex);
1566d093451SGreg Clayton 
157b9c1b51eSKate Stone     sect_to_addr_collection::iterator sta_pos =
158b9c1b51eSKate Stone         m_sect_to_addr.find(section_sp.get());
159b9c1b51eSKate Stone     if (sta_pos != m_sect_to_addr.end()) {
1603c94737fSGreg Clayton       ++unload_count;
1616d093451SGreg Clayton       addr_t load_addr = sta_pos->second;
1626d093451SGreg Clayton       m_sect_to_addr.erase(sta_pos);
1636d093451SGreg Clayton 
164b9c1b51eSKate Stone       addr_to_sect_collection::iterator ats_pos =
165b9c1b51eSKate Stone           m_addr_to_sect.find(load_addr);
1666d093451SGreg Clayton       if (ats_pos != m_addr_to_sect.end())
1676d093451SGreg Clayton         m_addr_to_sect.erase(ats_pos);
16817f69208SGreg Clayton     }
1697820bd1eSGreg Clayton   }
17017f69208SGreg Clayton   return unload_count;
17117f69208SGreg Clayton }
17217f69208SGreg Clayton 
SetSectionUnloaded(const lldb::SectionSP & section_sp,addr_t load_addr)173b9c1b51eSKate Stone bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp,
174b9c1b51eSKate Stone                                          addr_t load_addr) {
175a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::DynamicLoader);
17617f69208SGreg Clayton 
1773b7e1981SPavel Labath   if (log && log->GetVerbose()) {
178cbff63adSJim Ingham     ModuleSP module_sp = section_sp->GetModule();
179cbff63adSJim Ingham     std::string module_name("<Unknown>");
180b9c1b51eSKate Stone     if (module_sp) {
1817820bd1eSGreg Clayton       const FileSpec &module_file_spec(section_sp->GetModule()->GetFileSpec());
182cbff63adSJim Ingham       module_name = module_file_spec.GetPath();
183cbff63adSJim Ingham     }
18463e5fb76SJonas Devlieghere     LLDB_LOGF(
18563e5fb76SJonas Devlieghere         log,
186b9c1b51eSKate Stone         "SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64
187b9c1b51eSKate Stone         ")",
188324a1036SSaleem Abdulrasool         __FUNCTION__, static_cast<void *>(section_sp.get()),
189b9c1b51eSKate Stone         module_name.c_str(), section_sp->GetName().AsCString(), load_addr);
1908b2fe6dcSGreg Clayton   }
1916d093451SGreg Clayton   bool erased = false;
19216ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
193b9c1b51eSKate Stone   sect_to_addr_collection::iterator sta_pos =
194b9c1b51eSKate Stone       m_sect_to_addr.find(section_sp.get());
195b9c1b51eSKate Stone   if (sta_pos != m_sect_to_addr.end()) {
1966d093451SGreg Clayton     erased = true;
1976d093451SGreg Clayton     m_sect_to_addr.erase(sta_pos);
1986d093451SGreg Clayton   }
1996d093451SGreg Clayton 
2006d093451SGreg Clayton   addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
201b9c1b51eSKate Stone   if (ats_pos != m_addr_to_sect.end()) {
2026d093451SGreg Clayton     erased = true;
2036d093451SGreg Clayton     m_addr_to_sect.erase(ats_pos);
2046d093451SGreg Clayton   }
2056d093451SGreg Clayton 
2066d093451SGreg Clayton   return erased;
20717f69208SGreg Clayton }
20817f69208SGreg Clayton 
ResolveLoadAddress(addr_t load_addr,Address & so_addr,bool allow_section_end) const209c3c72122SPavel Labath bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, Address &so_addr,
210c3c72122SPavel Labath                                          bool allow_section_end) const {
21117f69208SGreg Clayton   // First find the top level section that this load address exists in
21216ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
213b9c1b51eSKate Stone   if (!m_addr_to_sect.empty()) {
214b9c1b51eSKate Stone     addr_to_sect_collection::const_iterator pos =
215b9c1b51eSKate Stone         m_addr_to_sect.lower_bound(load_addr);
216b9c1b51eSKate Stone     if (pos != m_addr_to_sect.end()) {
2176d093451SGreg Clayton       if (load_addr != pos->first && pos != m_addr_to_sect.begin())
21810177aa0SGreg Clayton         --pos;
21939f7ee86SGreg Clayton       const addr_t pos_load_addr = pos->first;
220b9c1b51eSKate Stone       if (load_addr >= pos_load_addr) {
22139f7ee86SGreg Clayton         addr_t offset = load_addr - pos_load_addr;
222c3c72122SPavel Labath         if (offset < pos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
22317f69208SGreg Clayton           // We have found the top level section, now we need to find the
22417f69208SGreg Clayton           // deepest child section.
225c3c72122SPavel Labath           return pos->second->ResolveContainedAddress(offset, so_addr,
226c3c72122SPavel Labath                                                       allow_section_end);
22717f69208SGreg Clayton         }
22817f69208SGreg Clayton       }
229b9c1b51eSKate Stone     } else {
23005097246SAdrian Prantl       // There are no entries that have an address that is >= load_addr, so we
23105097246SAdrian Prantl       // need to check the last entry on our collection.
232b9c1b51eSKate Stone       addr_to_sect_collection::const_reverse_iterator rpos =
233b9c1b51eSKate Stone           m_addr_to_sect.rbegin();
234b9c1b51eSKate Stone       if (load_addr >= rpos->first) {
2351c870d6eSGreg Clayton         addr_t offset = load_addr - rpos->first;
236c3c72122SPavel Labath         if (offset <
237c3c72122SPavel Labath             rpos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
238c5e9a7dcSGreg Clayton           // We have found the top level section, now we need to find the
239c5e9a7dcSGreg Clayton           // deepest child section.
240c3c72122SPavel Labath           return rpos->second->ResolveContainedAddress(offset, so_addr,
241c3c72122SPavel Labath                                                        allow_section_end);
242c5e9a7dcSGreg Clayton         }
243c5e9a7dcSGreg Clayton       }
244c5e9a7dcSGreg Clayton     }
245c5e9a7dcSGreg Clayton   }
24617f69208SGreg Clayton   so_addr.Clear();
24717f69208SGreg Clayton   return false;
24817f69208SGreg Clayton }
24910177aa0SGreg Clayton 
Dump(Stream & s,Target * target)250b9c1b51eSKate Stone void SectionLoadList::Dump(Stream &s, Target *target) {
25116ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
2526d093451SGreg Clayton   addr_to_sect_collection::const_iterator pos, end;
253b9c1b51eSKate Stone   for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end;
254b9c1b51eSKate Stone        ++pos) {
255b9c1b51eSKate Stone     s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first,
256b9c1b51eSKate Stone              static_cast<void *>(pos->second.get()));
2573a168297SPavel Labath     pos->second->Dump(s.AsRawOstream(), s.GetIndentLevel(), target, 0);
25810177aa0SGreg Clayton   }
25910177aa0SGreg Clayton }
260