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