1 | //===-- AddressRange.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/Core/AddressRange.h" |
10 | #include "lldb/Core/Module.h" |
11 | #include "lldb/Core/Section.h" |
12 | #include "lldb/Target/Target.h" |
13 | #include "lldb/Utility/ConstString.h" |
14 | #include "lldb/Utility/FileSpec.h" |
15 | #include "lldb/Utility/Stream.h" |
16 | #include "lldb/lldb-defines.h" |
17 | |
18 | #include "llvm/Support/Compiler.h" |
19 | |
20 | #include <memory> |
21 | |
22 | #include <cinttypes> |
23 | |
24 | namespace lldb_private { |
25 | class SectionList; |
26 | } |
27 | |
28 | using namespace lldb; |
29 | using namespace lldb_private; |
30 | |
31 | AddressRange::AddressRange() : m_base_addr() {} |
32 | |
33 | AddressRange::AddressRange(addr_t file_addr, addr_t byte_size, |
34 | const SectionList *section_list) |
35 | : m_base_addr(file_addr, section_list), m_byte_size(byte_size) {} |
36 | |
37 | AddressRange::AddressRange(const lldb::SectionSP §ion, addr_t offset, |
38 | addr_t byte_size) |
39 | : m_base_addr(section, offset), m_byte_size(byte_size) {} |
40 | |
41 | AddressRange::AddressRange(const Address &so_addr, addr_t byte_size) |
42 | : m_base_addr(so_addr), m_byte_size(byte_size) {} |
43 | |
44 | AddressRange::~AddressRange() = default; |
45 | |
46 | bool AddressRange::Contains(const Address &addr) const { |
47 | SectionSP range_sect_sp = GetBaseAddress().GetSection(); |
48 | SectionSP addr_sect_sp = addr.GetSection(); |
49 | if (range_sect_sp) { |
50 | if (!addr_sect_sp || |
51 | range_sect_sp->GetModule() != addr_sect_sp->GetModule()) |
52 | return false; // Modules do not match. |
53 | } else if (addr_sect_sp) { |
54 | return false; // Range has no module but "addr" does because addr has a |
55 | // section |
56 | } |
57 | // Either the modules match, or both have no module, so it is ok to compare |
58 | // the file addresses in this case only. |
59 | return ContainsFileAddress(so_addr: addr); |
60 | } |
61 | |
62 | bool AddressRange::ContainsFileAddress(const Address &addr) const { |
63 | if (addr.GetSection() == m_base_addr.GetSection()) |
64 | return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize(); |
65 | addr_t file_base_addr = GetBaseAddress().GetFileAddress(); |
66 | if (file_base_addr == LLDB_INVALID_ADDRESS) |
67 | return false; |
68 | |
69 | addr_t file_addr = addr.GetFileAddress(); |
70 | if (file_addr == LLDB_INVALID_ADDRESS) |
71 | return false; |
72 | |
73 | if (file_base_addr <= file_addr) |
74 | return (file_addr - file_base_addr) < GetByteSize(); |
75 | |
76 | return false; |
77 | } |
78 | |
79 | bool AddressRange::ContainsFileAddress(addr_t file_addr) const { |
80 | if (file_addr == LLDB_INVALID_ADDRESS) |
81 | return false; |
82 | |
83 | addr_t file_base_addr = GetBaseAddress().GetFileAddress(); |
84 | if (file_base_addr == LLDB_INVALID_ADDRESS) |
85 | return false; |
86 | |
87 | if (file_base_addr <= file_addr) |
88 | return (file_addr - file_base_addr) < GetByteSize(); |
89 | |
90 | return false; |
91 | } |
92 | |
93 | bool AddressRange::ContainsLoadAddress(const Address &addr, |
94 | Target *target) const { |
95 | if (addr.GetSection() == m_base_addr.GetSection()) |
96 | return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize(); |
97 | addr_t load_base_addr = GetBaseAddress().GetLoadAddress(target); |
98 | if (load_base_addr == LLDB_INVALID_ADDRESS) |
99 | return false; |
100 | |
101 | addr_t load_addr = addr.GetLoadAddress(target); |
102 | if (load_addr == LLDB_INVALID_ADDRESS) |
103 | return false; |
104 | |
105 | if (load_base_addr <= load_addr) |
106 | return (load_addr - load_base_addr) < GetByteSize(); |
107 | |
108 | return false; |
109 | } |
110 | |
111 | bool AddressRange::ContainsLoadAddress(addr_t load_addr, Target *target) const { |
112 | if (load_addr == LLDB_INVALID_ADDRESS) |
113 | return false; |
114 | |
115 | addr_t load_base_addr = GetBaseAddress().GetLoadAddress(target); |
116 | if (load_base_addr == LLDB_INVALID_ADDRESS) |
117 | return false; |
118 | |
119 | if (load_base_addr <= load_addr) |
120 | return (load_addr - load_base_addr) < GetByteSize(); |
121 | |
122 | return false; |
123 | } |
124 | |
125 | bool AddressRange::Extend(const AddressRange &rhs_range) { |
126 | addr_t lhs_end_addr = GetBaseAddress().GetFileAddress() + GetByteSize(); |
127 | addr_t rhs_base_addr = rhs_range.GetBaseAddress().GetFileAddress(); |
128 | |
129 | if (!ContainsFileAddress(addr: rhs_range.GetBaseAddress()) && |
130 | lhs_end_addr != rhs_base_addr) |
131 | // The ranges don't intersect at all on the right side of this range. |
132 | return false; |
133 | |
134 | addr_t rhs_end_addr = rhs_base_addr + rhs_range.GetByteSize(); |
135 | if (lhs_end_addr >= rhs_end_addr) |
136 | // The rhs range totally overlaps this one, nothing to add. |
137 | return false; |
138 | |
139 | m_byte_size += rhs_end_addr - lhs_end_addr; |
140 | return true; |
141 | } |
142 | |
143 | void AddressRange::Clear() { |
144 | m_base_addr.Clear(); |
145 | m_byte_size = 0; |
146 | } |
147 | |
148 | bool AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, |
149 | Address::DumpStyle fallback_style) const { |
150 | addr_t vmaddr = LLDB_INVALID_ADDRESS; |
151 | int addr_size = sizeof(addr_t); |
152 | if (target) |
153 | addr_size = target->GetArchitecture().GetAddressByteSize(); |
154 | |
155 | bool show_module = false; |
156 | switch (style) { |
157 | default: |
158 | break; |
159 | case Address::DumpStyleSectionNameOffset: |
160 | case Address::DumpStyleSectionPointerOffset: |
161 | s->PutChar(ch: '['); |
162 | m_base_addr.Dump(s, exe_scope: target, style, fallback_style); |
163 | s->PutChar(ch: '-'); |
164 | DumpAddress(s&: s->AsRawOstream(), addr: m_base_addr.GetOffset() + GetByteSize(), |
165 | addr_size); |
166 | s->PutChar(ch: ')'); |
167 | return true; |
168 | break; |
169 | |
170 | case Address::DumpStyleModuleWithFileAddress: |
171 | show_module = true; |
172 | [[fallthrough]]; |
173 | case Address::DumpStyleFileAddress: |
174 | vmaddr = m_base_addr.GetFileAddress(); |
175 | break; |
176 | |
177 | case Address::DumpStyleLoadAddress: |
178 | vmaddr = m_base_addr.GetLoadAddress(target); |
179 | break; |
180 | } |
181 | |
182 | if (vmaddr != LLDB_INVALID_ADDRESS) { |
183 | if (show_module) { |
184 | ModuleSP module_sp(GetBaseAddress().GetModule()); |
185 | if (module_sp) |
186 | s->Printf(format: "%s" , module_sp->GetFileSpec().GetFilename().AsCString( |
187 | value_if_empty: "<Unknown>" )); |
188 | } |
189 | DumpAddressRange(s&: s->AsRawOstream(), lo_addr: vmaddr, hi_addr: vmaddr + GetByteSize(), |
190 | addr_size); |
191 | return true; |
192 | } else if (fallback_style != Address::DumpStyleInvalid) { |
193 | return Dump(s, target, style: fallback_style, fallback_style: Address::DumpStyleInvalid); |
194 | } |
195 | |
196 | return false; |
197 | } |
198 | |
199 | void AddressRange::DumpDebug(Stream *s) const { |
200 | s->Printf(format: "%p: AddressRange section = %p, offset = 0x%16.16" PRIx64 |
201 | ", byte_size = 0x%16.16" PRIx64 "\n" , |
202 | static_cast<const void *>(this), |
203 | static_cast<void *>(m_base_addr.GetSection().get()), |
204 | m_base_addr.GetOffset(), GetByteSize()); |
205 | } |
206 | |