1 //===-- SectionLoadList.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Target/SectionLoadList.h"
10 
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/Section.h"
13 #include "lldb/Symbol/Block.h"
14 #include "lldb/Symbol/Symbol.h"
15 #include "lldb/Symbol/SymbolContext.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/Stream.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 SectionLoadList::SectionLoadList(const SectionLoadList &rhs)
23     : m_addr_to_sect(), m_sect_to_addr(), m_mutex() {
24   std::lock_guard<std::recursive_mutex> guard(rhs.m_mutex);
25   m_addr_to_sect = rhs.m_addr_to_sect;
26   m_sect_to_addr = rhs.m_sect_to_addr;
27 }
28 
29 void SectionLoadList::operator=(const SectionLoadList &rhs) {
30   std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
31   std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
32   m_addr_to_sect = rhs.m_addr_to_sect;
33   m_sect_to_addr = rhs.m_sect_to_addr;
34 }
35 
36 bool SectionLoadList::IsEmpty() const {
37   std::lock_guard<std::recursive_mutex> guard(m_mutex);
38   return m_addr_to_sect.empty();
39 }
40 
41 void SectionLoadList::Clear() {
42   std::lock_guard<std::recursive_mutex> guard(m_mutex);
43   m_addr_to_sect.clear();
44   m_sect_to_addr.clear();
45 }
46 
47 addr_t
48 SectionLoadList::GetSectionLoadAddress(const lldb::SectionSP &section) const {
49   // TODO: add support for the same section having multiple load addresses
50   addr_t section_load_addr = LLDB_INVALID_ADDRESS;
51   if (section) {
52     std::lock_guard<std::recursive_mutex> guard(m_mutex);
53     sect_to_addr_collection::const_iterator pos =
54         m_sect_to_addr.find(section.get());
55 
56     if (pos != m_sect_to_addr.end())
57       section_load_addr = pos->second;
58   }
59   return section_load_addr;
60 }
61 
62 bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP &section,
63                                             addr_t load_addr,
64                                             bool warn_multiple) {
65   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
66   ModuleSP module_sp(section->GetModule());
67 
68   if (module_sp) {
69     LLDB_LOGV(log, "(section = {0} ({1}.{2}), load_addr = {3:x}) module = {4}",
70               section.get(), module_sp->GetFileSpec(), section->GetName(),
71               load_addr, module_sp.get());
72 
73     if (section->GetByteSize() == 0)
74       return false; // No change
75 
76     // Fill in the section -> load_addr map
77     std::lock_guard<std::recursive_mutex> guard(m_mutex);
78     sect_to_addr_collection::iterator sta_pos =
79         m_sect_to_addr.find(section.get());
80     if (sta_pos != m_sect_to_addr.end()) {
81       if (load_addr == sta_pos->second)
82         return false; // No change...
83       else
84         sta_pos->second = load_addr;
85     } else
86       m_sect_to_addr[section.get()] = load_addr;
87 
88     // Fill in the load_addr -> section map
89     addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
90     if (ats_pos != m_addr_to_sect.end()) {
91       // Some sections are ok to overlap, and for others we should warn. When
92       // we have multiple load addresses that correspond to a section, we will
93       // always attribute the section to the be last section that claims it
94       // exists at that address. Sometimes it is ok for more that one section
95       // to be loaded at a specific load address, and other times it isn't. The
96       // "warn_multiple" parameter tells us if we should warn in this case or
97       // not. The DynamicLoader plug-in subclasses should know which sections
98       // should warn and which shouldn't (darwin shared cache modules all
99       // shared the same "__LINKEDIT" sections, so the dynamic loader can pass
100       // false for "warn_multiple").
101       if (warn_multiple && section != ats_pos->second) {
102         ModuleSP module_sp(section->GetModule());
103         if (module_sp) {
104           ModuleSP curr_module_sp(ats_pos->second->GetModule());
105           if (curr_module_sp) {
106             module_sp->ReportWarning(
107                 "address 0x%16.16" PRIx64
108                 " maps to more than one section: %s.%s and %s.%s",
109                 load_addr, module_sp->GetFileSpec().GetFilename().GetCString(),
110                 section->GetName().GetCString(),
111                 curr_module_sp->GetFileSpec().GetFilename().GetCString(),
112                 ats_pos->second->GetName().GetCString());
113           }
114         }
115       }
116       ats_pos->second = section;
117     } else
118       m_addr_to_sect[load_addr] = section;
119     return true; // Changed
120 
121   } else {
122     if (log) {
123       log->Printf(
124           "SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64
125           ") error: module has been deleted",
126           __FUNCTION__, static_cast<void *>(section.get()),
127           section->GetName().AsCString(), load_addr);
128     }
129   }
130   return false;
131 }
132 
133 size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp) {
134   size_t unload_count = 0;
135 
136   if (section_sp) {
137     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
138 
139     if (log && log->GetVerbose()) {
140       ModuleSP module_sp = section_sp->GetModule();
141       std::string module_name("<Unknown>");
142       if (module_sp) {
143         const FileSpec &module_file_spec(
144             section_sp->GetModule()->GetFileSpec());
145         module_name = module_file_spec.GetPath();
146       }
147       log->Printf("SectionLoadList::%s (section = %p (%s.%s))", __FUNCTION__,
148                   static_cast<void *>(section_sp.get()), module_name.c_str(),
149                   section_sp->GetName().AsCString());
150     }
151 
152     std::lock_guard<std::recursive_mutex> guard(m_mutex);
153 
154     sect_to_addr_collection::iterator sta_pos =
155         m_sect_to_addr.find(section_sp.get());
156     if (sta_pos != m_sect_to_addr.end()) {
157       ++unload_count;
158       addr_t load_addr = sta_pos->second;
159       m_sect_to_addr.erase(sta_pos);
160 
161       addr_to_sect_collection::iterator ats_pos =
162           m_addr_to_sect.find(load_addr);
163       if (ats_pos != m_addr_to_sect.end())
164         m_addr_to_sect.erase(ats_pos);
165     }
166   }
167   return unload_count;
168 }
169 
170 bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP &section_sp,
171                                          addr_t load_addr) {
172   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
173 
174   if (log && log->GetVerbose()) {
175     ModuleSP module_sp = section_sp->GetModule();
176     std::string module_name("<Unknown>");
177     if (module_sp) {
178       const FileSpec &module_file_spec(section_sp->GetModule()->GetFileSpec());
179       module_name = module_file_spec.GetPath();
180     }
181     log->Printf(
182         "SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64
183         ")",
184         __FUNCTION__, static_cast<void *>(section_sp.get()),
185         module_name.c_str(), section_sp->GetName().AsCString(), load_addr);
186   }
187   bool erased = false;
188   std::lock_guard<std::recursive_mutex> guard(m_mutex);
189   sect_to_addr_collection::iterator sta_pos =
190       m_sect_to_addr.find(section_sp.get());
191   if (sta_pos != m_sect_to_addr.end()) {
192     erased = true;
193     m_sect_to_addr.erase(sta_pos);
194   }
195 
196   addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
197   if (ats_pos != m_addr_to_sect.end()) {
198     erased = true;
199     m_addr_to_sect.erase(ats_pos);
200   }
201 
202   return erased;
203 }
204 
205 bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, Address &so_addr,
206                                          bool allow_section_end) const {
207   // First find the top level section that this load address exists in
208   std::lock_guard<std::recursive_mutex> guard(m_mutex);
209   if (!m_addr_to_sect.empty()) {
210     addr_to_sect_collection::const_iterator pos =
211         m_addr_to_sect.lower_bound(load_addr);
212     if (pos != m_addr_to_sect.end()) {
213       if (load_addr != pos->first && pos != m_addr_to_sect.begin())
214         --pos;
215       const addr_t pos_load_addr = pos->first;
216       if (load_addr >= pos_load_addr) {
217         addr_t offset = load_addr - pos_load_addr;
218         if (offset < pos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
219           // We have found the top level section, now we need to find the
220           // deepest child section.
221           return pos->second->ResolveContainedAddress(offset, so_addr,
222                                                       allow_section_end);
223         }
224       }
225     } else {
226       // There are no entries that have an address that is >= load_addr, so we
227       // need to check the last entry on our collection.
228       addr_to_sect_collection::const_reverse_iterator rpos =
229           m_addr_to_sect.rbegin();
230       if (load_addr >= rpos->first) {
231         addr_t offset = load_addr - rpos->first;
232         if (offset <
233             rpos->second->GetByteSize() + (allow_section_end ? 1 : 0)) {
234           // We have found the top level section, now we need to find the
235           // deepest child section.
236           return rpos->second->ResolveContainedAddress(offset, so_addr,
237                                                        allow_section_end);
238         }
239       }
240     }
241   }
242   so_addr.Clear();
243   return false;
244 }
245 
246 void SectionLoadList::Dump(Stream &s, Target *target) {
247   std::lock_guard<std::recursive_mutex> guard(m_mutex);
248   addr_to_sect_collection::const_iterator pos, end;
249   for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end;
250        ++pos) {
251     s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first,
252              static_cast<void *>(pos->second.get()));
253     pos->second->Dump(&s, target, 0);
254   }
255 }
256