1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <algorithm>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <libdwarf/dwarf.h>
22 #include "debug_info.h"
23 #include "utils/logger.h"
24
25 namespace panda {
26
27 class DwarfGuard {
28 public:
DwarfGuard(Dwarf_Debug dbg,void * mem,Dwarf_Unsigned tag)29 DwarfGuard(Dwarf_Debug dbg, void *mem, Dwarf_Unsigned tag) : dbg_(dbg), mem_(mem), tag_(tag) {}
30
Release()31 void Release()
32 {
33 mem_ = nullptr;
34 }
35
Reset(void * new_mem)36 void Reset(void *new_mem)
37 {
38 if (mem_ != new_mem && mem_ != nullptr) {
39 dwarf_dealloc(dbg_, mem_, tag_);
40 mem_ = new_mem;
41 }
42 }
43
~DwarfGuard()44 ~DwarfGuard()
45 {
46 Reset(nullptr);
47 }
48
49 NO_MOVE_SEMANTIC(DwarfGuard);
50 NO_COPY_SEMANTIC(DwarfGuard);
51
52 private:
53 Dwarf_Debug dbg_;
54 void *mem_;
55 Dwarf_Unsigned tag_;
56 };
57
58 template <class F>
59 class AtReturn {
60 public:
AtReturn(F func)61 explicit AtReturn(F func) : func_(func) {}
62
~AtReturn()63 ~AtReturn()
64 {
65 func_();
66 }
67
68 NO_MOVE_SEMANTIC(AtReturn);
69 NO_COPY_SEMANTIC(AtReturn);
70
71 private:
72 F func_;
73 };
74
FreeAranges(Dwarf_Debug dbg,Dwarf_Arange * aranges,Dwarf_Signed count)75 static void FreeAranges(Dwarf_Debug dbg, Dwarf_Arange *aranges, Dwarf_Signed count)
76 {
77 for (Dwarf_Signed i = 0; i < count; ++i) {
78 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
79 dwarf_dealloc(dbg, aranges[i], DW_DLA_ARANGE);
80 }
81 dwarf_dealloc(dbg, aranges, DW_DLA_LIST);
82 }
83
SkipCuHeaders(Dwarf_Debug dbg)84 static void SkipCuHeaders(Dwarf_Debug dbg)
85 {
86 Dwarf_Unsigned cu_header_idx;
87 Dwarf_Half cu_type;
88 while (dwarf_next_cu_header_d(dbg, static_cast<Dwarf_Bool>(true), nullptr, nullptr, nullptr, nullptr, nullptr,
89 nullptr, nullptr, nullptr, &cu_header_idx, &cu_type, nullptr) != DW_DLV_NO_ENTRY) {
90 }
91 }
92
DwarfErrorHandler(Dwarf_Error err,Dwarf_Ptr errarg)93 static void DwarfErrorHandler(Dwarf_Error err, [[maybe_unused]] Dwarf_Ptr errarg)
94 {
95 LOG(ERROR, RUNTIME) << "libdwarf error: " << dwarf_errmsg(err);
96 }
97
GetDieRange(Dwarf_Die die,Dwarf_Addr * out_low_pc,Dwarf_Addr * out_high_pc)98 static bool GetDieRange(Dwarf_Die die, Dwarf_Addr *out_low_pc, Dwarf_Addr *out_high_pc)
99 {
100 Dwarf_Addr low_pc = DW_DLV_BADADDR;
101 Dwarf_Addr high_pc = 0;
102 Dwarf_Half form = 0;
103 Dwarf_Form_Class formclass;
104
105 if (dwarf_lowpc(die, &low_pc, nullptr) != DW_DLV_OK ||
106 dwarf_highpc_b(die, &high_pc, &form, &formclass, nullptr) != DW_DLV_OK) {
107 return false;
108 }
109 if (formclass == DW_FORM_CLASS_CONSTANT) {
110 high_pc += low_pc;
111 }
112 *out_low_pc = low_pc;
113 *out_high_pc = high_pc;
114 return true;
115 }
116
117 template <class F>
IterateDieRanges(Dwarf_Debug dbg,Dwarf_Die die,F func)118 bool IterateDieRanges(Dwarf_Debug dbg, Dwarf_Die die, F func)
119 {
120 Dwarf_Addr low_pc = DW_DLV_BADADDR;
121 Dwarf_Addr high_pc = DW_DLV_BADADDR;
122
123 if (GetDieRange(die, &low_pc, &high_pc)) {
124 return func(low_pc, high_pc);
125 }
126
127 Dwarf_Attribute attr;
128 if (dwarf_attr(die, DW_AT_ranges, &attr, nullptr) != DW_DLV_OK) {
129 return false;
130 }
131 DwarfGuard g(dbg, attr, DW_DLA_ATTR);
132 Dwarf_Unsigned offset = 0;
133 Dwarf_Addr base_addr = 0;
134 if (low_pc != DW_DLV_BADADDR) {
135 base_addr = low_pc;
136 }
137 Dwarf_Signed count = 0;
138 Dwarf_Ranges *buf = nullptr;
139 if (dwarf_global_formref(attr, &offset, nullptr) == DW_DLV_OK &&
140 dwarf_get_ranges_a(dbg, offset, die, &buf, &count, nullptr, nullptr) == DW_DLV_OK) {
141 AtReturn r([dbg, buf, count]() { dwarf_ranges_dealloc(dbg, buf, count); });
142 Span<Dwarf_Ranges> ranges(buf, count);
143 for (const Dwarf_Ranges &range : ranges) {
144 if (range.dwr_type == DW_RANGES_ENTRY) {
145 Dwarf_Addr rng_low_pc = base_addr + range.dwr_addr1;
146 Dwarf_Addr rng_high_pc = base_addr + range.dwr_addr2;
147 if (func(rng_low_pc, rng_high_pc)) {
148 return true;
149 }
150 } else if (range.dwr_type == DW_RANGES_ADDRESS_SELECTION) {
151 base_addr = range.dwr_addr2;
152 } else {
153 break;
154 }
155 }
156 }
157 return false;
158 }
159
~CompUnit()160 DebugInfo::CompUnit::~CompUnit()
161 {
162 if (line_ctx_ != nullptr) {
163 dwarf_srclines_dealloc_b(line_ctx_);
164 }
165 if (cu_die_ != nullptr) {
166 dwarf_dealloc(dbg_, cu_die_, DW_DLA_DIE);
167 }
168 }
169
GetLineContext()170 Dwarf_Line_Context DebugInfo::CompUnit::GetLineContext()
171 {
172 if (line_ctx_ != nullptr) {
173 return line_ctx_;
174 }
175 // Decode line number information for the whole compilation unit
176 Dwarf_Unsigned version = 0;
177 Dwarf_Small table_count = 0;
178 if (dwarf_srclines_b(cu_die_, &version, &table_count, &line_ctx_, nullptr) != DW_DLV_OK) {
179 line_ctx_ = nullptr;
180 }
181 return line_ctx_;
182 }
183
Destroy()184 void DebugInfo::Destroy()
185 {
186 if (dbg_ == nullptr) {
187 return;
188 }
189 if (aranges_ != nullptr) {
190 FreeAranges(dbg_, aranges_, arange_count_);
191 }
192 aranges_ = nullptr;
193 arange_count_ = 0;
194 cu_list_.clear();
195 ranges_.clear();
196 dwarf_finish(dbg_, nullptr);
197 close(fd_);
198 fd_ = INVALID_FD;
199 dbg_ = nullptr;
200 }
201
ReadFromFile(const char * filename)202 DebugInfo::ErrorCode DebugInfo::ReadFromFile(const char *filename)
203 {
204 Dwarf_Error err = nullptr;
205 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-signed-bitwise)
206 fd_ = open(filename, O_RDONLY | O_CLOEXEC);
207 int res = dwarf_init(fd_, DW_DLC_READ, DwarfErrorHandler, nullptr, &dbg_, &err);
208 if (res != DW_DLV_OK) {
209 // TODO(audovichenko): Libdwarf has a bug (memory leak).
210 // In case dwarf_init fails it allocates memory for the error and returns it in 'err' variable.
211 // But since dbg is NULL, dwarf_dealloc just returns in case of dbg == nullptr and doesn't free this memory
212 // A possible solution is to use 20201201 version and call dwarf_dealloc.
213 free(err); // NOLINT(cppcoreguidelines-no-malloc)
214 close(fd_);
215 fd_ = INVALID_FD;
216 dbg_ = nullptr;
217 }
218 if (res == DW_DLV_ERROR) {
219 return ERROR;
220 }
221 if (res == DW_DLV_NO_ENTRY) {
222 return NO_DEBUG_INFO;
223 }
224 // Aranges (address ranges) is an entity which help us to find the compilation unit quickly (something like index)
225 if (dwarf_get_aranges(dbg_, &aranges_, &arange_count_, nullptr) != DW_DLV_OK) {
226 aranges_ = nullptr;
227 arange_count_ = 0;
228 }
229 return SUCCESS;
230 }
231
GetSrcLocation(uintptr_t pc,std::string * function,std::string * src_file,uint32_t * line)232 bool DebugInfo::GetSrcLocation(uintptr_t pc, std::string *function, std::string *src_file, uint32_t *line)
233 {
234 if (dbg_ == nullptr) {
235 return false;
236 }
237 // Debug information have hierarchical structure.
238 // Each node is represented by DIE (debug information entity).
239 // .debug_info has a list of DIE which corresponds to compilation units (object files).
240 // Mapping pc to function is to find the compilation unit DIE and then find the subprogram DIE.
241 // From the subprogram DIE we get the function name.
242 // Line information is available for compilation unit DIEs. So we decode lines for the whole
243 // compilation unit and find the corresponding line and file which matches the pc.
244 //
245 // You could use objdump --dwarf=info <object file> to view available debug information.
246
247 Range range(pc, pc);
248 auto it = ranges_.upper_bound(range);
249 if (it == ranges_.end() || !it->Contain(pc)) {
250 Dwarf_Die cu_die = nullptr;
251 if (!FindCompUnitByPc(pc, &cu_die)) {
252 return false;
253 }
254 cu_list_.emplace_back(CompUnit(cu_die, dbg_));
255 auto ranges = &ranges_;
256 auto cu = &cu_list_.back();
257 IterateDieRanges(dbg_, cu_die, [ranges, cu](Dwarf_Addr low_pc, Dwarf_Addr high_pc) {
258 ranges->insert(Range(low_pc, high_pc, cu));
259 return false;
260 });
261 TraverseChildren(cu, cu_die);
262 }
263 it = ranges_.upper_bound(range);
264 if (it == ranges_.end() || !it->Contain(pc)) {
265 return false;
266 }
267
268 ASSERT(it->GetCu() != nullptr);
269 *function = it->GetFunction();
270 // Find the corresponding line number and source file.
271 GetSrcFileAndLine(pc, it->GetCu()->GetLineContext(), src_file, line);
272 return true;
273 }
274
FindCompUnitByPc(uintptr_t pc,Dwarf_Die * cu_die)275 bool DebugInfo::FindCompUnitByPc(uintptr_t pc, Dwarf_Die *cu_die)
276 {
277 if (aranges_ != nullptr) {
278 Dwarf_Arange arange = nullptr;
279 Dwarf_Off offset = 0;
280 if (dwarf_get_arange(aranges_, arange_count_, pc, &arange, nullptr) == DW_DLV_OK &&
281 dwarf_get_cu_die_offset(arange, &offset, nullptr) == DW_DLV_OK &&
282 dwarf_offdie(dbg_, offset, cu_die, nullptr) == DW_DLV_OK) {
283 return true;
284 }
285 }
286
287 // No aranges are available or we can't find the corresponding arange. Iterate over all compilation units.
288 // Its slow but works.
289 Dwarf_Unsigned cu_header_idx;
290 Dwarf_Half cu_type;
291 int res = dwarf_next_cu_header_d(dbg_, static_cast<Dwarf_Bool>(true), nullptr, nullptr, nullptr, nullptr, nullptr,
292 nullptr, nullptr, nullptr, &cu_header_idx, &cu_type, nullptr);
293 while (res == DW_DLV_OK) {
294 Dwarf_Die die = nullptr;
295 if (dwarf_siblingof_b(dbg_, nullptr, static_cast<Dwarf_Bool>(true), &die, nullptr) == DW_DLV_OK) {
296 if (PcMatches(pc, die)) {
297 *cu_die = die;
298 // Skip the rest cu headers because next time we need to stat search from the beginning.
299 SkipCuHeaders(dbg_);
300 return true;
301 }
302 dwarf_dealloc(dbg_, die, DW_DLA_DIE);
303 }
304 res = dwarf_next_cu_header_d(dbg_, static_cast<Dwarf_Bool>(true), nullptr, nullptr, nullptr, nullptr, nullptr,
305 nullptr, nullptr, nullptr, &cu_header_idx, &cu_type, nullptr);
306 }
307 return false;
308 }
309
TraverseChildren(CompUnit * cu,Dwarf_Die die)310 void DebugInfo::TraverseChildren(CompUnit *cu, Dwarf_Die die)
311 {
312 Dwarf_Die child_die = nullptr;
313 if (dwarf_child(die, &child_die, nullptr) != DW_DLV_OK) {
314 return;
315 }
316 TraverseSiblings(cu, child_die);
317 }
318
TraverseSiblings(CompUnit * cu,Dwarf_Die die)319 void DebugInfo::TraverseSiblings(CompUnit *cu, Dwarf_Die die)
320 {
321 DwarfGuard g(dbg_, die, DW_DLA_DIE);
322 Dwarf_Half tag = 0;
323 int res;
324 do {
325 if (dwarf_tag(die, &tag, nullptr) != DW_DLV_OK) {
326 return;
327 }
328 if ((tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine)) {
329 Dwarf_Addr low_pc = DW_DLV_BADADDR;
330 Dwarf_Addr high_pc = 0;
331
332 if (GetDieRange(die, &low_pc, &high_pc)) {
333 std::string fname;
334 GetFunctionName(die, &fname);
335 AddFunction(cu, low_pc, high_pc, fname);
336 }
337 }
338 TraverseChildren(cu, die);
339 Dwarf_Die sibling = nullptr;
340 res = dwarf_siblingof_b(dbg_, die, static_cast<Dwarf_Bool>(true), &sibling, nullptr);
341 if (res == DW_DLV_OK) {
342 g.Reset(sibling);
343 die = sibling;
344 }
345 } while (res == DW_DLV_OK);
346 }
347
AddFunction(CompUnit * cu,Dwarf_Addr low_pc,Dwarf_Addr high_pc,const std::string & function)348 void DebugInfo::AddFunction(CompUnit *cu, Dwarf_Addr low_pc, Dwarf_Addr high_pc, const std::string &function)
349 {
350 auto it = ranges_.upper_bound(Range(low_pc, low_pc));
351 ASSERT(it != ranges_.end());
352 Range range(low_pc, high_pc, cu, function);
353 if (it->Contain(range)) {
354 Range enclosing = *it;
355 ranges_.erase(it);
356 if (enclosing.GetLowPc() < low_pc) {
357 ranges_.insert(Range(enclosing.GetLowPc(), low_pc, enclosing.GetCu(), enclosing.GetFunction()));
358 }
359 ranges_.insert(range);
360 if (high_pc < enclosing.GetHighPc()) {
361 ranges_.insert(Range(high_pc, enclosing.GetHighPc(), enclosing.GetCu(), enclosing.GetFunction()));
362 }
363 } else if (range.Contain(*it)) {
364 ranges_.insert(Range(range.GetLowPc(), it->GetLowPc(), cu, function));
365 ranges_.insert(Range(it->GetHighPc(), range.GetHighPc(), cu, function));
366 } else if (high_pc <= it->GetLowPc()) {
367 ranges_.insert(range);
368 }
369 }
370
GetFunctionName(Dwarf_Die die,std::string * function)371 void DebugInfo::GetFunctionName(Dwarf_Die die, std::string *function)
372 {
373 char *name = nullptr;
374
375 // Prefer linkage name instead of name
376 // Linkage name is a mangled name which contains information about enclosing class,
377 // return type, parameters and so on.
378 // The name which is stored in DW_AT_name attribute is only a function name.
379 if (dwarf_die_text(die, DW_AT_linkage_name, &name, nullptr) == DW_DLV_OK ||
380 dwarf_diename(die, &name, nullptr) == DW_DLV_OK) {
381 DwarfGuard g(dbg_, name, DW_DLA_STRING);
382 *function = name;
383 return;
384 }
385
386 Dwarf_Off off = 0;
387 Dwarf_Attribute attr = nullptr;
388 Dwarf_Die abs_orig_die = nullptr;
389 // If there is no name | linkage_name the function may be inlined.
390 // Try to get it from the abstract origin
391 if (dwarf_attr(die, DW_AT_abstract_origin, &attr, nullptr) == DW_DLV_OK) {
392 DwarfGuard ag(dbg_, attr, DW_DLA_ATTR);
393 if (dwarf_global_formref(attr, &off, nullptr) == DW_DLV_OK &&
394 dwarf_offdie(dbg_, off, &abs_orig_die, nullptr) == DW_DLV_OK) {
395 DwarfGuard dg(dbg_, abs_orig_die, DW_DLA_DIE);
396 GetFunctionName(abs_orig_die, function);
397 return;
398 }
399 }
400
401 // If there is no name | linkage_name try to get it from the specification.
402 Dwarf_Die spec_die = nullptr;
403 if (dwarf_attr(die, DW_AT_specification, &attr, nullptr) == DW_DLV_OK) {
404 DwarfGuard ag(dbg_, attr, DW_DLA_ATTR);
405 if (dwarf_global_formref(attr, &off, nullptr) == DW_DLV_OK &&
406 dwarf_offdie(dbg_, off, &spec_die, nullptr) == DW_DLV_OK) {
407 DwarfGuard dg(dbg_, spec_die, DW_DLA_DIE);
408 GetFunctionName(spec_die, function);
409 }
410 }
411 }
412
GetSrcFileAndLine(uintptr_t pc,Dwarf_Line_Context line_ctx,std::string * out_src_file,uint32_t * out_line)413 bool DebugInfo::GetSrcFileAndLine(uintptr_t pc, Dwarf_Line_Context line_ctx, std::string *out_src_file,
414 uint32_t *out_line)
415 {
416 if (line_ctx == nullptr) {
417 return false;
418 }
419 Dwarf_Line *line_buf = nullptr;
420 Dwarf_Signed line_buf_size = 0;
421 if (dwarf_srclines_from_linecontext(line_ctx, &line_buf, &line_buf_size, nullptr) != DW_DLV_OK) {
422 return false;
423 }
424 Span<Dwarf_Line> lines(line_buf, line_buf_size);
425 Dwarf_Addr prev_line_pc = 0;
426 Dwarf_Line prev_line = nullptr;
427 bool found = false;
428 for (auto it = lines.begin(); it != lines.end() && !found; ++it) {
429 Dwarf_Line line = *it;
430 Dwarf_Addr line_pc = 0;
431 dwarf_lineaddr(line, &line_pc, nullptr);
432 if (pc == line_pc) {
433 GetSrcFileAndLine(GetLastLineWithPc(pc, it, lines.end()), out_src_file, out_line);
434 found = true;
435 } else if (prev_line != nullptr && prev_line_pc < pc && pc < line_pc) {
436 GetSrcFileAndLine(prev_line, out_src_file, out_line);
437 found = true;
438 } else {
439 Dwarf_Bool is_line_end;
440 dwarf_lineendsequence(line, &is_line_end, nullptr);
441 if (is_line_end != 0) {
442 prev_line = nullptr;
443 } else {
444 prev_line_pc = line_pc;
445 prev_line = line;
446 }
447 }
448 }
449 return found;
450 }
451
GetLastLineWithPc(Dwarf_Addr pc,Span<Dwarf_Line>::ConstIterator it,Span<Dwarf_Line>::ConstIterator end)452 Dwarf_Line DebugInfo::GetLastLineWithPc(Dwarf_Addr pc, Span<Dwarf_Line>::ConstIterator it,
453 Span<Dwarf_Line>::ConstIterator end)
454 {
455 Dwarf_Addr line_pc = 0;
456 auto next = std::next(it);
457 while (next != end) {
458 dwarf_lineaddr(*next, &line_pc, nullptr);
459 if (pc != line_pc) {
460 return *it;
461 }
462 it = next;
463 ++next;
464 }
465 return *it;
466 }
467
GetSrcFileAndLine(Dwarf_Line line,std::string * out_src_file,uint32_t * out_line)468 void DebugInfo::GetSrcFileAndLine(Dwarf_Line line, std::string *out_src_file, uint32_t *out_line)
469 {
470 Dwarf_Unsigned ln;
471 dwarf_lineno(line, &ln, nullptr);
472 *out_line = ln;
473 char *src_file = nullptr;
474 if (dwarf_linesrc(line, &src_file, nullptr) == DW_DLV_OK) {
475 *out_src_file = src_file;
476 DwarfGuard g(dbg_, src_file, DW_DLA_STRING);
477 } else {
478 dwarf_linesrc(line, &src_file, nullptr);
479 *out_src_file = src_file;
480 DwarfGuard g(dbg_, src_file, DW_DLA_STRING);
481 }
482 }
483
PcMatches(uintptr_t pc,Dwarf_Die die)484 bool DebugInfo::PcMatches(uintptr_t pc, Dwarf_Die die)
485 {
486 Dwarf_Addr low_pc = DW_DLV_BADADDR;
487 Dwarf_Addr high_pc = 0;
488 return GetDieRangeForPc(pc, die, &low_pc, &high_pc);
489 }
490
GetDieRange(Dwarf_Die die,Dwarf_Addr * out_low_pc,Dwarf_Addr * out_high_pc)491 bool DebugInfo::GetDieRange(Dwarf_Die die, Dwarf_Addr *out_low_pc, Dwarf_Addr *out_high_pc)
492 {
493 Dwarf_Addr low_pc = DW_DLV_BADADDR;
494 Dwarf_Addr high_pc = 0;
495 Dwarf_Half form = 0;
496 Dwarf_Form_Class formclass;
497
498 if (dwarf_lowpc(die, &low_pc, nullptr) != DW_DLV_OK ||
499 dwarf_highpc_b(die, &high_pc, &form, &formclass, nullptr) != DW_DLV_OK) {
500 return false;
501 }
502 if (formclass == DW_FORM_CLASS_CONSTANT) {
503 high_pc += low_pc;
504 }
505 *out_low_pc = low_pc;
506 *out_high_pc = high_pc;
507 return true;
508 }
509
GetDieRangeForPc(uintptr_t pc,Dwarf_Die die,Dwarf_Addr * out_low_pc,Dwarf_Addr * out_high_pc)510 bool DebugInfo::GetDieRangeForPc(uintptr_t pc, Dwarf_Die die, Dwarf_Addr *out_low_pc, Dwarf_Addr *out_high_pc)
511 {
512 Dwarf_Addr low_pc = DW_DLV_BADADDR;
513 Dwarf_Addr high_pc = 0;
514
515 if (GetDieRange(die, &low_pc, &high_pc) && (*out_low_pc <= pc && pc < *out_high_pc)) {
516 *out_low_pc = low_pc;
517 *out_high_pc = high_pc;
518 return true;
519 }
520
521 Dwarf_Attribute attr;
522 if (dwarf_attr(die, DW_AT_ranges, &attr, nullptr) == DW_DLV_OK) {
523 DwarfGuard g(dbg_, attr, DW_DLA_ATTR);
524 Dwarf_Unsigned offset;
525 Dwarf_Addr base_addr = 0;
526 if (low_pc != DW_DLV_BADADDR) {
527 base_addr = low_pc;
528 }
529 Dwarf_Signed count = 0;
530 Dwarf_Ranges *ranges = nullptr;
531 if (dwarf_global_formref(attr, &offset, nullptr) == DW_DLV_OK &&
532 dwarf_get_ranges_a(dbg_, offset, die, &ranges, &count, nullptr, nullptr) == DW_DLV_OK) {
533 Dwarf_Debug dbg = dbg_;
534 AtReturn r([dbg, ranges, count]() { dwarf_ranges_dealloc(dbg, ranges, count); });
535 return FindRangeForPc(pc, Span<Dwarf_Ranges>(ranges, count), base_addr, out_low_pc, out_high_pc);
536 }
537 }
538 return false;
539 }
540
FindRangeForPc(uintptr_t pc,const Span<Dwarf_Ranges> & ranges,Dwarf_Addr base_addr,Dwarf_Addr * out_low_pc,Dwarf_Addr * out_high_pc)541 bool DebugInfo::FindRangeForPc(uintptr_t pc, const Span<Dwarf_Ranges> &ranges, Dwarf_Addr base_addr,
542 Dwarf_Addr *out_low_pc, Dwarf_Addr *out_high_pc)
543 {
544 for (const Dwarf_Ranges &range : ranges) {
545 if (range.dwr_type == DW_RANGES_ENTRY) {
546 Dwarf_Addr rng_low_pc = base_addr + range.dwr_addr1;
547 Dwarf_Addr rng_high_pc = base_addr + range.dwr_addr2;
548 if (rng_low_pc <= pc && pc < rng_high_pc) {
549 *out_low_pc = rng_low_pc;
550 *out_high_pc = rng_high_pc;
551 return true;
552 }
553 } else if (range.dwr_type == DW_RANGES_ADDRESS_SELECTION) {
554 base_addr = range.dwr_addr2;
555 } else {
556 break;
557 }
558 }
559 return false;
560 }
561
562 } // namespace panda
563