xref: /aosp_15_r20/external/cronet/base/debug/dwarf_line_no.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/debug/dwarf_line_no.h"
6 
7 #include "partition_alloc/pointers/raw_ref.h"
8 
9 #ifdef USE_SYMBOLIZE
10 #include <algorithm>
11 #include <charconv>
12 #include <cstdint>
13 #include <limits>
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include "base/debug/buffered_dwarf_reader.h"
20 #include "base/third_party/symbolize/symbolize.h"
21 #include "partition_alloc/pointers/raw_ptr.h"
22 
23 namespace base {
24 namespace debug {
25 
26 namespace {
27 
28 constexpr uint64_t kMaxOffset = std::numeric_limits<uint64_t>::max();
29 
30 // These numbers are suitable for most compilation units for chrome and
31 // content_shell. If a compilation unit has bigger number of directories or
32 // filenames, the additional directories/filenames will be ignored, and the
33 // stack frames pointing to these directories/filenames will not get line
34 // numbers. We can't set these numbers too big because they affect the size of
35 // ProgramInfo which is allocated in the stack.
36 constexpr int kMaxDirectories = 128;
37 constexpr size_t kMaxFilenames = 512;
38 
39 // DWARF-4 line number program header, section 6.2.4
40 struct ProgramInfo {
41   uint64_t header_length;
42   uint64_t start_offset;
43   uint64_t end_offset;
44   uint8_t minimum_instruction_length;
45   uint8_t maximum_operations_per_instruction;
46   uint8_t default_is_stmt;
47   int8_t line_base;
48   uint8_t line_range;
49   uint8_t opcode_base;
50   uint8_t standard_opcode_lengths[256];
51   uint8_t include_directories_table_offset;
52   uint8_t file_names_table_offset;
53 
54   // Store the directories as offsets.
55   int num_directories = 1;
56   uint64_t directory_offsets[kMaxDirectories];
57   uint64_t directory_sizes[kMaxDirectories];
58 
59   // Store the file number table offsets.
60   mutable unsigned int num_filenames = 1;
61   mutable uint64_t filename_offsets[kMaxFilenames];
62   mutable uint8_t filename_dirs[kMaxFilenames];
63 
OpcodeToAdvancebase::debug::__anon7dac112c0111::ProgramInfo64   unsigned int OpcodeToAdvance(uint8_t adjusted_opcode) const {
65     // Special opcodes advance line numbers by an amount based on line_range
66     // and opcode_base. This calculation is taken from 6.2.5.1.
67     return static_cast<unsigned int>(adjusted_opcode) / line_range;
68   }
69 };
70 
71 // DWARF-4 line number program registers, section 6.2.2
72 struct LineNumberRegisters {
73   // During the line number program evaluation, some instructions perform a
74   // "commit" which is when the registers have finished calculating a new row in
75   // the line-number table. This callback is executed and can be viewed as a
76   // iterator over all rows in the line number table.
77   class OnCommit {
78    public:
79     virtual void Do(LineNumberRegisters* registers) = 0;
80   };
81 
82   raw_ptr<OnCommit> on_commit;
LineNumberRegistersbase::debug::__anon7dac112c0111::LineNumberRegisters83   LineNumberRegisters(ProgramInfo info, OnCommit* on_commit)
84       : on_commit(on_commit), is_stmt(info.default_is_stmt) {}
85 
86   // Current program counter.
87   uintptr_t address = 0;
88 
89   // For VLIW architectures, the index of the operation in the VLIW instruction.
90   unsigned int op_index = 0;
91 
92   // Identifies the source file relating to the address in the DWARF File name
93   // table.
94   uint64_t file = 0;
95 
96   // Identifies the line number. Starts at 1. Can become 0 if instruction does
97   // not match any line in the file.
98   uint64_t line = 1;
99 
100   // Identifies the column within the source line. Starts at 1 though "0"
101   // also means "left edge" of the line.
102   uint64_t column = 0;
103 
104   // Boolean determining if this is a recommended spot for a breakpoint.
105   // Should be initialized by the program header.
106   bool is_stmt = false;
107 
108   // Indicates start of a basic block.
109   bool basic_block = false;
110 
111   // Indicates first byte after a sequence of machine instructions.
112   bool end_sequence = false;
113 
114   // Indicates this may be where execution should stop if trying to break for
115   // entering a function.
116   bool prologue_end = false;
117 
118   // Indicates this may be where execution should stop if trying to break for
119   // exiting a function.
120   bool epilogue_begin = false;
121 
122   // Identifier for the instruction set of the current address.
123   uint64_t isa = 0;
124 
125   // Identifies which block the current instruction belongs to.
126   uint64_t discriminator = 0;
127 
128   // Values from the previously committed line. See OnCommit interface for more
129   // details. This conceptually should be a copy of the whole
130   // LineNumberRegisters but since only 4 pieces of data are needed, hacking
131   // it inline was easier.
132   uintptr_t last_address = 0;
133   uint64_t last_file = 0;
134   uint64_t last_line = 0;
135   uint64_t last_column = 0;
136 
137   // This is the magical calculation for decompressing the line-number
138   // information. The `program_info` provides the parameters for the formula
139   // and the `op_advance` is the input value. See DWARF-4 sections 6.2.5.1 for
140   // the formula.
OpAdvancebase::debug::__anon7dac112c0111::LineNumberRegisters141   void OpAdvance(const ProgramInfo* program_info, uint64_t op_advance) {
142     address += program_info->minimum_instruction_length *
143                ((op_index + op_advance) /
144                 program_info->maximum_operations_per_instruction);
145 
146     op_index = (op_index + op_advance) %
147                program_info->maximum_operations_per_instruction;
148   }
149 
150   // Committing a line means the calculation has landed on a stable set of
151   // values that represent an actual entry in the line number table.
CommitLinebase::debug::__anon7dac112c0111::LineNumberRegisters152   void CommitLine() {
153     on_commit->Do(this);
154 
155     // Inlined or compiler generator code may have line number 0 which isn't
156     // useful to the user. Better to go up one line number.
157     if (line != 0) {
158       last_address = address;
159       last_file = file;
160       last_column = column;
161       last_line = line;
162     }
163   }
164 };
165 
166 struct LineNumberInfo {
167   uint64_t pc = 0;
168   uint64_t line = 0;
169   uint64_t column = 0;
170 
171   // Offsets here are to the file table and directory table arrays inside the
172   // ProgramInfo.
173   uint64_t module_dir_offset = 0;
174   uint64_t dir_size = 0;
175   uint64_t module_filename_offset = 0;
176 };
177 
178 // Evaluates a Line Number Program as defined by the rules in section 6.2.5.
EvaluateLineNumberProgram(const int fd,LineNumberInfo * info,uint64_t base_address,uint64_t start,const ProgramInfo & program_info)179 void EvaluateLineNumberProgram(const int fd,
180                                LineNumberInfo* info,
181                                uint64_t base_address,
182                                uint64_t start,
183                                const ProgramInfo& program_info) {
184   BufferedDwarfReader reader(fd, start);
185   uint64_t module_relative_pc = info->pc - base_address;
186 
187   // Helper that records the line-number table entry corresponding with the
188   // `module_relative_pc`. This is the thing that actually finds the line
189   // number for an address.
190   struct OnCommitImpl : public LineNumberRegisters::OnCommit {
191    private:
192     raw_ptr<LineNumberInfo> info;
193     uint64_t module_relative_pc;
194     const raw_ref<const ProgramInfo> program_info;
195 
196    public:
197     OnCommitImpl(LineNumberInfo* info,
198                  uint64_t module_relative_pc,
199                  const ProgramInfo& program_info)
200         : info(info),
201           module_relative_pc(module_relative_pc),
202           program_info(program_info) {}
203 
204     void Do(LineNumberRegisters* registers) override {
205       // When a line is committed, the program counter needs to check if it is
206       // in the [last_address, cur_addres) range. If yes, then the line pertains
207       // to the program counter.
208       if (registers->last_address == 0) {
209         // This is the first table entry so by definition, nothing is in its
210         // range.
211         return;
212       }
213 
214       // If module_relative_pc is out of range, skip.
215       if (module_relative_pc < registers->last_address ||
216           module_relative_pc >= registers->address)
217         return;
218 
219       if (registers->last_file < program_info->num_filenames) {
220         info->line = registers->last_line;
221         info->column = registers->last_column;
222 
223         // Since DW_AT_name in the compile_unit is optional, it may be empty. If
224         // it is, guess that the file in entry 1 is the name. This does not
225         // follow spec, but seems to be common behavior. See the following LLVM
226         // bug for more info: https://reviews.llvm.org/D11003
227         if (registers->last_file == 0 &&
228             program_info->filename_offsets[0] == 0 &&
229             1 < program_info->num_filenames) {
230           program_info->filename_offsets[0] = program_info->filename_offsets[1];
231           program_info->filename_dirs[0] = program_info->filename_dirs[1];
232         }
233 
234         if (registers->last_file < kMaxFilenames) {
235           info->module_filename_offset =
236               program_info->filename_offsets[registers->last_file];
237 
238           uint8_t dir = program_info->filename_dirs[registers->last_file];
239           info->module_dir_offset = program_info->directory_offsets[dir];
240           info->dir_size = program_info->directory_sizes[dir];
241         }
242       }
243     }
244   } on_commit(info, module_relative_pc, program_info);
245 
246   LineNumberRegisters registers(program_info, &on_commit);
247 
248   // Special opcode range is [program_info.opcode_base, 255].
249   // Lines can be max incremented by [line_base + line range - 1].
250   // opcode = (desired line increment - line_base) + (line_range * operation
251   // advance) + opcode_base.
252   uint8_t opcode;
253   while (reader.position() < program_info.end_offset && info->line == 0) {
254     if (!reader.ReadInt8(opcode))
255       return;
256 
257     // It's SPECIAL OPCODE TIME!. They're so special that they make up the
258     // vast majority of the opcodes and are the first thing described in the
259     // documentation.
260     //
261     // See DWARF-4 spec 6.2.5.1.
262     if (opcode >= program_info.opcode_base) {
263       uint8_t adjusted_opcode = opcode - program_info.opcode_base;
264       registers.OpAdvance(&program_info,
265                           program_info.OpcodeToAdvance(adjusted_opcode));
266       const int line_adjust =
267           program_info.line_base + (adjusted_opcode % program_info.line_range);
268       if (line_adjust < 0) {
269         if (static_cast<uint64_t>(-line_adjust) > registers.line)
270           return;
271         registers.line -= static_cast<uint64_t>(-line_adjust);
272       } else {
273         registers.line += static_cast<uint64_t>(line_adjust);
274       }
275       registers.basic_block = false;
276       registers.prologue_end = false;
277       registers.epilogue_begin = false;
278       registers.discriminator = 0;
279       registers.CommitLine();
280     } else {
281       // Standard opcodes
282       switch (opcode) {
283         case 0: {
284           // Extended opcode.
285           uint64_t extended_opcode;
286           uint64_t extended_opcode_length;
287           if (!reader.ReadLeb128(extended_opcode_length))
288             return;
289           uint64_t next_opcode = reader.position() + extended_opcode_length;
290           if (!reader.ReadLeb128(extended_opcode))
291             return;
292           switch (extended_opcode) {
293             case 1: {
294               // DW_LNE_end_sequence
295               registers.end_sequence = true;
296               registers.CommitLine();
297               registers = LineNumberRegisters(program_info, &on_commit);
298               break;
299             }
300 
301             case 2: {
302               // DW_LNE_set_address
303               uint32_t value;
304               if (!reader.ReadInt32(value))
305                 return;
306               registers.address = value;
307               registers.op_index = 0;
308               break;
309             }
310 
311             case 3: {
312               // DW_LNE_define_file
313               //
314               // This should only get used if the filename table itself is null.
315               // Record the module offset for the string and then drop the data.
316               uint64_t filename_offset = reader.position();
317               reader.ReadCString(program_info.end_offset, nullptr, 0);
318 
319               // dir index
320               uint64_t value;
321               if (!reader.ReadLeb128(value))
322                 return;
323               size_t cur_filename = program_info.num_filenames;
324               if (cur_filename < kMaxFilenames && value < kMaxDirectories) {
325                 ++program_info.num_filenames;
326                 // Store the offset from the start of file and skip the data to
327                 // save memory.
328                 program_info.filename_offsets[cur_filename] = filename_offset;
329                 program_info.filename_dirs[cur_filename] =
330                     static_cast<uint8_t>(value);
331               }
332 
333               // modification time
334               if (!reader.ReadLeb128(value))
335                 return;
336 
337               // source file length
338               if (!reader.ReadLeb128(value))
339                 return;
340               break;
341             }
342 
343             case 4: {
344               // DW_LNE_set_discriminator
345               uint64_t value;
346               if (!reader.ReadLeb128(value))
347                 return;
348               registers.discriminator = value;
349               break;
350             }
351 
352             default:
353               abort();
354           }
355 
356           // Skip any padding bytes in extended opcode.
357           reader.set_position(next_opcode);
358           break;
359         }
360 
361         case 1: {
362           // DW_LNS_copy. This commits the registers to the line number table.
363           registers.CommitLine();
364           registers.discriminator = 0;
365           registers.basic_block = false;
366           registers.prologue_end = false;
367           registers.epilogue_begin = false;
368           break;
369         }
370 
371         case 2: {
372           // DW_LNS_advance_pc
373           uint64_t op_advance;
374           if (!reader.ReadLeb128(op_advance))
375             return;
376           registers.OpAdvance(&program_info, op_advance);
377           break;
378         }
379 
380         case 3: {
381           // DW_LNS_advance_line
382           int64_t line_advance;
383           if (!reader.ReadLeb128(line_advance))
384             return;
385           if (line_advance < 0) {
386             if (static_cast<uint64_t>(-line_advance) > registers.line)
387               return;
388             registers.line -= static_cast<uint64_t>(-line_advance);
389           } else {
390             registers.line += static_cast<uint64_t>(line_advance);
391           }
392           break;
393         }
394 
395         case 4: {
396           // DW_LNS_set_file
397           uint64_t value;
398           if (!reader.ReadLeb128(value))
399             return;
400           registers.file = value;
401           break;
402         }
403 
404         case 5: {
405           // DW_LNS_set_column
406           uint64_t value;
407           if (!reader.ReadLeb128(value))
408             return;
409           registers.column = value;
410           break;
411         }
412 
413         case 6:
414           // DW_LNS_negate_stmt
415           registers.is_stmt = !registers.is_stmt;
416           break;
417 
418         case 7:
419           // DW_LNS_set_basic_block
420           registers.basic_block = true;
421           break;
422 
423         case 8:
424           // DW_LNS_const_add_pc
425           registers.OpAdvance(
426               &program_info,
427               program_info.OpcodeToAdvance(255 - program_info.opcode_base));
428           break;
429 
430         case 9: {
431           // DW_LNS_fixed_advance_pc
432           uint16_t value;
433           if (!reader.ReadInt16(value))
434             return;
435           registers.address += value;
436           registers.op_index = 0;
437           break;
438         }
439 
440         case 10:
441           // DW_LNS_set_prologue_end
442           registers.prologue_end = true;
443           break;
444 
445         case 11:
446           // DW_LNS_set_epilogue_begin
447           registers.epilogue_begin = true;
448           break;
449 
450         case 12: {
451           // DW_LNS_set_isa
452           uint64_t value;
453           if (!reader.ReadLeb128(value))
454             return;
455           registers.isa = value;
456           break;
457         }
458 
459         default:
460           abort();
461       }
462     }
463   }
464 }
465 
466 // Parses a 32-bit DWARF-4 line number program header per section 6.2.4.
467 // `cu_name_offset` is the module offset for the 0th entry of the file table.
ParseDwarf4ProgramInfo(BufferedDwarfReader * reader,bool is_64bit,uint64_t cu_name_offset,ProgramInfo * program_info)468 bool ParseDwarf4ProgramInfo(BufferedDwarfReader* reader,
469                             bool is_64bit,
470                             uint64_t cu_name_offset,
471                             ProgramInfo* program_info) {
472   if (!reader->ReadOffset(is_64bit, program_info->header_length))
473     return false;
474   program_info->start_offset = reader->position() + program_info->header_length;
475 
476   if (!reader->ReadInt8(program_info->minimum_instruction_length) ||
477       !reader->ReadInt8(program_info->maximum_operations_per_instruction) ||
478       !reader->ReadInt8(program_info->default_is_stmt) ||
479       !reader->ReadInt8(program_info->line_base) ||
480       !reader->ReadInt8(program_info->line_range) ||
481       !reader->ReadInt8(program_info->opcode_base)) {
482     return false;
483   }
484 
485   for (int i = 0; i < (program_info->opcode_base - 1); i++) {
486     if (!reader->ReadInt8(program_info->standard_opcode_lengths[i]))
487       return false;
488   }
489 
490   // Table ends with a single null line. This basically means search for 2
491   // contiguous empty bytes.
492   uint8_t last = 0, cur = 0;
493   for (;;) {
494     // Read a byte.
495     last = cur;
496     if (!reader->ReadInt8(cur))
497       return false;
498 
499     if (last == 0 && cur == 0) {
500       // We're at the last entry where it's a double null.
501       break;
502     }
503 
504     // Read in all of the filename.
505     int cur_dir = program_info->num_directories;
506     if (cur_dir < kMaxDirectories) {
507       ++program_info->num_directories;
508       // "-1" is because we have already read the first byte above.
509       program_info->directory_offsets[cur_dir] = reader->position() - 1;
510       program_info->directory_sizes[cur_dir] = 1;
511     }
512     do {
513       if (!reader->ReadInt8(cur))
514         return false;
515       if (cur_dir < kMaxDirectories)
516         ++program_info->directory_sizes[cur_dir];
517     } while (cur != '\0');
518   }
519 
520   // Read filename table line-by-line.
521   last = 0;
522   cur = 0;
523   for (;;) {
524     // Read a byte.
525     last = cur;
526     if (!reader->ReadInt8(cur))
527       return false;
528 
529     if (last == 0 && cur == 0) {
530       // We're at the last entry where it's a double null.
531       break;
532     }
533 
534     // Read in all of the filename. "-1" is because we have already read the
535     // first byte of the filename above.
536     uint64_t filename_offset = reader->position() - 1;
537     do {
538       if (!reader->ReadInt8(cur))
539         return false;
540     } while (cur != '\0');
541 
542     uint64_t value;
543 
544     // Dir index
545     if (!reader->ReadLeb128(value))
546       return false;
547     size_t cur_filename = program_info->num_filenames;
548     if (cur_filename < kMaxFilenames && value < kMaxDirectories) {
549       ++program_info->num_filenames;
550       program_info->filename_offsets[cur_filename] = filename_offset;
551       program_info->filename_dirs[cur_filename] = static_cast<uint8_t>(value);
552     }
553 
554     // Modification time
555     if (!reader->ReadLeb128(value))
556       return false;
557 
558     // Bytes in file.
559     if (!reader->ReadLeb128(value))
560       return false;
561   }
562 
563   // Set up the 0th filename.
564   program_info->filename_offsets[0] = cu_name_offset;
565   program_info->filename_dirs[0] = 0;
566   program_info->directory_offsets[0] = 0;
567 
568   return true;
569 }
570 
571 // Returns the offset of the next byte to read.
572 // `program_info.program_end` is guaranteed to be initlialized to either
573 // `kMaxOffset` if the program length could not be processed, or to
574 // the byte after the end of this program.
ReadProgramInfo(const int fd,uint64_t start,uint64_t cu_name_offset,ProgramInfo * program_info)575 bool ReadProgramInfo(const int fd,
576                      uint64_t start,
577                      uint64_t cu_name_offset,
578                      ProgramInfo* program_info) {
579   BufferedDwarfReader reader(fd, start);
580   program_info->end_offset = kMaxOffset;
581 
582   // Note that 64-bit dwarf does NOT imply a 64-bit binary and vice-versa. In
583   // fact many 64-bit binaries use 32-bit dwarf encoding.
584   bool is_64bit = false;
585   uint64_t data_length;
586   if (!reader.ReadInitialLength(is_64bit, data_length)) {
587     return false;
588   }
589 
590   // Set the program end. This allows the search to recover by skipping an
591   // unparsable program.
592   program_info->end_offset = reader.position() + data_length;
593 
594   uint16_t version;
595   if (!reader.ReadInt16(version)) {
596     return false;
597   }
598 
599   if (version == 4) {
600     return ParseDwarf4ProgramInfo(&reader, is_64bit, cu_name_offset,
601                                   program_info);
602   }
603 
604   // Currently does not support other DWARF versions.
605   return false;
606 }
607 
608 // Attempts to find line-number info for all of |info|. Returns the number of
609 // entries that do not have info yet.
GetLineNumbersInProgram(const int fd,LineNumberInfo * info,uint64_t base_address,uint64_t start,uint64_t cu_name_offset)610 uint64_t GetLineNumbersInProgram(const int fd,
611                                  LineNumberInfo* info,
612                                  uint64_t base_address,
613                                  uint64_t start,
614                                  uint64_t cu_name_offset) {
615   // Open the program.
616   ProgramInfo program_info;
617   if (ReadProgramInfo(fd, start, cu_name_offset, &program_info)) {
618     EvaluateLineNumberProgram(fd, info, base_address, program_info.start_offset,
619                               program_info);
620   }
621 
622   return program_info.end_offset;
623 }
624 
625 // Scans the .debug_abbrev entry until it finds the Attribute List matching the
626 // `wanted_abbreviation_code`. This is called when parsing a DIE in .debug_info.
AdvancedReaderToAttributeList(BufferedDwarfReader & reader,uint64_t table_end,uint64_t wanted_abbreviation_code,uint64_t & tag,bool & has_children)627 bool AdvancedReaderToAttributeList(BufferedDwarfReader& reader,
628                                    uint64_t table_end,
629                                    uint64_t wanted_abbreviation_code,
630                                    uint64_t& tag,
631                                    bool& has_children) {
632   // Abbreviation Table entries are:
633   //   LEB128 - abbreviation code
634   //   LEB128 - the entry's tag
635   //   1 byte - DW_CHILDREN_yes or DW_CHILDREN_no for if entry has children.
636   //   [LEB128, LEB128] -- repeated set of attribute + form values in LEB128
637   //   [0, 0] -- null entry terminating list is 2 LEB128 0s.
638   while (reader.position() < table_end) {
639     uint64_t abbreviation_code;
640     if (!reader.ReadLeb128(abbreviation_code)) {
641       return false;
642     }
643 
644     if (!reader.ReadLeb128(tag)) {
645       return false;
646     }
647 
648     uint8_t raw_has_children;
649     if (!reader.ReadInt8(raw_has_children)) {
650       return false;
651     }
652     if (raw_has_children == 0) {
653       has_children = false;
654     } else if (raw_has_children == 1) {
655       has_children = true;
656     } else {
657       return false;
658     }
659 
660     if (abbreviation_code == wanted_abbreviation_code) {
661       return true;
662     }
663 
664     // Incorrect Abbreviation entry. Skip all of its attributes.
665     uint64_t attr;
666     uint64_t form;
667     do {
668       if (!reader.ReadLeb128(attr) || !reader.ReadLeb128(form)) {
669         return false;
670       }
671     } while (attr != 0 || form != 0);
672   }
673 
674   return false;
675 }
676 
677 // This reads through a .debug_info compile unit entry to try and extract
678 // the `cu_name_offset` as well as the `debug_line_offset` (offset into the
679 // .debug_lines table` corresponding to `pc`.
680 //
681 // The .debug_info sections are a packed set of bytes whose format is defined
682 // by a corresponding .debug_abbrev entry. Basically .debug_abbrev describes
683 // a struct and .debug_info has a header that tells which struct it is followed
684 // by a bunch of bytes.
685 //
686 // The control flow is to find the .debug_abbrev entry for each .debug_info
687 // entry, then walk through the .debug_abbrev entry to parse the bytes of the
688 // .debug_info entry. A successful parse calculates the address range that the
689 // .debug_info entry covers. When that is retrieved, `pc` can be compared to
690 // the range and a corresponding .debug_info can be found.
691 //
692 // The `debug_info_start` be the start of the whole .debug_info section or an
693 // offset into the section if it was known ahead of time (perhaps by consulting
694 // .debug_aranges).
695 //
696 // To fully interpret this data, the .debug_ranges and .debug_str sections
697 // also need to be interpreted.
GetCompileUnitName(int fd,uint64_t debug_info_start,uint64_t debug_info_end,uint64_t pc,uint64_t module_base_address,uint64_t * debug_line_offset,uint64_t * cu_name_offset)698 bool GetCompileUnitName(int fd,
699                         uint64_t debug_info_start,
700                         uint64_t debug_info_end,
701                         uint64_t pc,
702                         uint64_t module_base_address,
703                         uint64_t* debug_line_offset,
704                         uint64_t* cu_name_offset) {
705   // Ensure defined `cu_name_offset` in case DW_AT_name is missing.
706   *cu_name_offset = 0;
707 
708   // Open .debug_info and .debug_abbrev as both are needed to find the
709   // DW_AT_name for the DW_TAG_compile_unit or DW_TAG_partial_unit
710   // corresponding to the given address.
711 
712   ElfW(Shdr) debug_abbrev;
713   constexpr static char kDebugAbbrevSectionName[] = ".debug_abbrev";
714   if (!google::GetSectionHeaderByName(fd, kDebugAbbrevSectionName,
715                                       sizeof(kDebugAbbrevSectionName),
716                                       &debug_abbrev)) {
717     return false;
718   }
719   uint64_t debug_abbrev_end = debug_abbrev.sh_offset + debug_abbrev.sh_size;
720 
721   ElfW(Shdr) debug_str;
722   constexpr static char kDebugStrSectionName[] = ".debug_str";
723   if (!google::GetSectionHeaderByName(
724           fd, kDebugStrSectionName, sizeof(kDebugStrSectionName), &debug_str)) {
725     return false;
726   }
727   uint64_t debug_str_end = debug_str.sh_offset + debug_str.sh_size;
728 
729   ElfW(Shdr) debug_ranges;
730   constexpr static char kDebugRangesSectionName[] = ".debug_ranges";
731   if (!google::GetSectionHeaderByName(fd, kDebugRangesSectionName,
732                                       sizeof(kDebugRangesSectionName),
733                                       &debug_ranges)) {
734     return false;
735   }
736   uint64_t debug_ranges_end = debug_ranges.sh_offset + debug_ranges.sh_size;
737 
738   // Iterate Compile Units.
739   uint64_t next_compilation_unit = kMaxOffset;
740   for (BufferedDwarfReader reader(fd, debug_info_start);
741        reader.position() < debug_info_end;
742        reader.set_position(next_compilation_unit)) {
743     bool is_64bit;
744     uint64_t length;
745     uint16_t dwarf_version;
746     uint64_t abbrev_offset;
747     uint8_t address_size;
748     if (!reader.ReadCommonHeader(is_64bit, length, dwarf_version, abbrev_offset,
749                                  address_size, next_compilation_unit)) {
750       return false;
751     }
752 
753     // Compilation Unit Header parsed. Now read the first tag which is either a
754     // DW_TAG_compile_unit or DW_TAG_partial_unit. The entry type is designated
755     // by a LEB128 number that needs to be cross-referenced in the abbreviations
756     // table to understand the format of the rest of the entry.
757     uint64_t abbreviation_code;
758     if (!reader.ReadLeb128(abbreviation_code)) {
759       return false;
760     }
761 
762     // Find entry in the abbreviation table.
763     BufferedDwarfReader abbrev_reader(fd,
764                                       debug_abbrev.sh_offset + abbrev_offset);
765     uint64_t tag;
766     bool has_children;
767     AdvancedReaderToAttributeList(abbrev_reader, debug_abbrev_end,
768                                   abbreviation_code, tag, has_children);
769 
770     // Ignore if it has children.
771     static constexpr int kDW_TAG_compile_unit = 0x11;
772     static constexpr int kDW_TAG_partial_unit = 0x3c;
773     if (tag != kDW_TAG_compile_unit && tag != kDW_TAG_partial_unit) {
774       return false;
775     }
776 
777     // Use table to parse the name, high, and low attributes.
778     static constexpr int kDW_AT_name = 0x3;        // string
779     static constexpr int kDW_AT_stmt_list = 0x10;  // lineptr
780     static constexpr int kDW_AT_low_pc = 0x11;     // address
781     static constexpr int kDW_AT_high_pc = 0x12;    // address, constant
782     static constexpr int kDW_AT_ranges = 0x55;     // rangelistptr
783     uint64_t attr;
784     uint64_t form;
785     uint64_t low_pc = 0;
786     uint64_t high_pc = 0;
787     bool high_pc_is_offset = false;
788     bool is_found_in_range = false;
789     do {
790       if (!abbrev_reader.ReadLeb128(attr)) {
791         return false;
792       }
793       if (!abbrev_reader.ReadLeb128(form)) {
794         return false;
795       }
796       // Table from 7.5.4, Figure 20.
797       enum Form {
798         kDW_FORM_addr = 0x01,
799         kDW_FORM_block2 = 0x03,
800         kDW_FORM_block4 = 0x04,
801         kDW_FORM_data2 = 0x05,
802         kDW_FORM_data4 = 0x06,
803         kDW_FORM_data8 = 0x07,
804         kDW_FORM_string = 0x08,
805         kDW_FORM_block = 0x09,
806         kDW_FORM_block1 = 0x0a,
807         kDW_FORM_data1 = 0x0b,
808         kDW_FORM_flag = 0x0c,
809         kDW_FORM_sdata = 0x0d,
810         kDW_FORM_strp = 0x0e,
811         kDW_FORM_udata = 0x0f,
812         kDW_FORM_ref_addr = 0x10,
813         kDW_FORM_ref1 = 0x11,
814         kDW_FORM_ref2 = 0x12,
815         kDW_FORM_ref4 = 0x13,
816         kDW_FORM_ref8 = 0x14,
817         kDW_FORM_ref_udata = 0x15,
818         kDW_FORM_ref_indrect = 0x16,
819         kDW_FORM_sec_offset = 0x17,
820         kDW_FORM_exprloc = 0x18,
821         kDW_FORM_flag_present = 0x19,
822         kDW_FORM_ref_sig8 = 0x20,
823       };
824 
825       switch (form) {
826         case kDW_FORM_string: {
827           // Read the value into if necessary `out`
828           if (attr == kDW_AT_name) {
829             *cu_name_offset = reader.position();
830           }
831           if (!reader.ReadCString(debug_info_end, nullptr, 0)) {
832             return false;
833           }
834         } break;
835 
836         case kDW_FORM_strp: {
837           uint64_t strp_offset;
838           if (!reader.ReadOffset(is_64bit, strp_offset)) {
839             return false;
840           }
841 
842           if (attr == kDW_AT_name) {
843             uint64_t pos = debug_str.sh_offset + strp_offset;
844             if (pos >= debug_str_end) {
845               return false;
846             }
847             *cu_name_offset = pos;
848           }
849         } break;
850 
851         case kDW_FORM_addr: {
852           uint64_t address;
853           if (!reader.ReadAddress(address_size, address)) {
854             return false;
855           }
856 
857           if (attr == kDW_AT_low_pc) {
858             low_pc = address;
859           } else if (attr == kDW_AT_high_pc) {
860             high_pc_is_offset = false;
861             high_pc = address;
862           }
863         } break;
864 
865         case kDW_FORM_data1: {
866           uint8_t data;
867           if (!reader.ReadInt8(data)) {
868             return false;
869           }
870           if (attr == kDW_AT_high_pc) {
871             high_pc_is_offset = true;
872             high_pc = data;
873           }
874         } break;
875 
876         case kDW_FORM_data2: {
877           uint16_t data;
878           if (!reader.ReadInt16(data)) {
879             return false;
880           }
881           if (attr == kDW_AT_high_pc) {
882             high_pc_is_offset = true;
883             high_pc = data;
884           }
885         } break;
886 
887         case kDW_FORM_data4: {
888           uint32_t data;
889           if (!reader.ReadInt32(data)) {
890             return false;
891           }
892           if (attr == kDW_AT_high_pc) {
893             high_pc_is_offset = true;
894             high_pc = data;
895           }
896         } break;
897 
898         case kDW_FORM_data8: {
899           uint64_t data;
900           if (!reader.ReadInt64(data)) {
901             return false;
902           }
903           if (attr == kDW_AT_high_pc) {
904             high_pc_is_offset = true;
905             high_pc = data;
906           }
907         } break;
908 
909         case kDW_FORM_sdata: {
910           int64_t data;
911           if (!reader.ReadLeb128(data)) {
912             return false;
913           }
914           if (attr == kDW_AT_high_pc) {
915             high_pc_is_offset = true;
916             high_pc = static_cast<uint64_t>(data);
917           }
918         } break;
919 
920         case kDW_FORM_udata: {
921           uint64_t data;
922           if (!reader.ReadLeb128(data)) {
923             return false;
924           }
925           if (attr == kDW_AT_high_pc) {
926             high_pc_is_offset = true;
927             high_pc = data;
928           }
929         } break;
930 
931         case kDW_FORM_ref_addr:
932         case kDW_FORM_sec_offset: {
933           uint64_t value;
934           if (!reader.ReadOffset(is_64bit, value)) {
935             return false;
936           }
937 
938           if (attr == kDW_AT_ranges) {
939             uint64_t current_base_address = module_base_address;
940             BufferedDwarfReader ranges_reader(fd,
941                                               debug_ranges.sh_offset + value);
942 
943             while (ranges_reader.position() < debug_ranges_end) {
944               // Ranges are 2 addresses in size.
945               uint64_t range_start;
946               uint64_t range_end;
947               if (!ranges_reader.ReadAddress(address_size, range_start)) {
948                 return false;
949               }
950               if (!ranges_reader.ReadAddress(address_size, range_end)) {
951                 return false;
952               }
953               uint64_t relative_pc = pc - current_base_address;
954 
955               if (range_start == 0 && range_end == 0) {
956                 if (!is_found_in_range) {
957                   // Time to go to the next iteration.
958                   goto next_cu;
959                 }
960                 break;
961               } else if (((address_size == 4) &&
962                           (range_start == 0xffffffffUL)) ||
963                          ((address_size == 8) &&
964                           (range_start == 0xffffffffffffffffULL))) {
965                 // Check if this is a new base add value. 2.17.3
966                 current_base_address = range_end;
967               } else {
968                 if (relative_pc >= range_start && relative_pc < range_end) {
969                   is_found_in_range = true;
970                   break;
971                 }
972               }
973             }
974           } else if (attr == kDW_AT_stmt_list) {
975             *debug_line_offset = value;
976           }
977         } break;
978 
979         case kDW_FORM_flag:
980         case kDW_FORM_ref1:
981         case kDW_FORM_block1: {
982           uint8_t dummy;
983           if (!reader.ReadInt8(dummy)) {
984             return false;
985           }
986         } break;
987 
988         case kDW_FORM_ref2:
989         case kDW_FORM_block2: {
990           uint16_t dummy;
991           if (!reader.ReadInt16(dummy)) {
992             return false;
993           }
994         } break;
995 
996         case kDW_FORM_ref4:
997         case kDW_FORM_block4: {
998           uint32_t dummy;
999           if (!reader.ReadInt32(dummy)) {
1000             return false;
1001           }
1002         } break;
1003 
1004         case kDW_FORM_ref8: {
1005           uint64_t dummy;
1006           if (!reader.ReadInt64(dummy)) {
1007             return false;
1008           }
1009         } break;
1010 
1011         case kDW_FORM_ref_udata:
1012         case kDW_FORM_block: {
1013           uint64_t dummy;
1014           if (!reader.ReadLeb128(dummy)) {
1015             return false;
1016           }
1017         } break;
1018 
1019         case kDW_FORM_exprloc: {
1020           uint64_t value;
1021           if (!reader.ReadLeb128(value)) {
1022             return false;
1023           }
1024           reader.set_position(reader.position() + value);
1025         } break;
1026       }
1027     } while (attr != 0 || form != 0);
1028 
1029     // Because attributes can be in any order, most of the computations (minus
1030     // checking range list entries) cannot happen until everything is parsed for
1031     // the one .debug_info entry. Do the analysis here.
1032     if (is_found_in_range) {
1033       // Well formed compile_unit and partial_unit tags either have a
1034       // DT_AT_ranges entry or an DT_AT_low_pc entiry. If is_found_in_range
1035       // matched as true, then this entry matches the given pc.
1036       return true;
1037     }
1038 
1039     // If high_pc_is_offset is 0, it was never found in the DIE. This indicates
1040     // a single address entry. Only look at the low_pc.
1041     {
1042       uint64_t module_relative_pc = pc - module_base_address;
1043       if (high_pc == 0 && module_relative_pc != low_pc) {
1044         goto next_cu;
1045       }
1046 
1047       // Otherwise this is a contiguous range DIE. Normalize the meaning of the
1048       // high_pc field and check if it contains the pc.
1049       if (high_pc_is_offset) {
1050         high_pc = low_pc + high_pc;
1051         high_pc_is_offset = false;
1052       }
1053 
1054       if (module_relative_pc >= low_pc && module_relative_pc < high_pc) {
1055         return true;
1056       }
1057     }
1058 
1059     // Not found.
1060   next_cu:;
1061   }
1062   return false;
1063 }
1064 
1065 // Thin wrapper over `GetCompileUnitName` that opens the .debug_info section.
ReadCompileUnit(int fd,uint64_t pc,uint64_t cu_offset,uint64_t base_address,uint64_t * debug_line_offset,uint64_t * cu_name_offset)1066 bool ReadCompileUnit(int fd,
1067                      uint64_t pc,
1068                      uint64_t cu_offset,
1069                      uint64_t base_address,
1070                      uint64_t* debug_line_offset,
1071                      uint64_t* cu_name_offset) {
1072   if (cu_offset == 0) {
1073     return false;
1074   }
1075 
1076   ElfW(Shdr) debug_info;
1077   constexpr static char kDebugInfoSectionName[] = ".debug_info";
1078   if (!google::GetSectionHeaderByName(fd, kDebugInfoSectionName,
1079                                       sizeof(kDebugInfoSectionName),
1080                                       &debug_info)) {
1081     return false;
1082   }
1083   uint64_t debug_info_end = debug_info.sh_offset + debug_info.sh_size;
1084 
1085   return GetCompileUnitName(fd, debug_info.sh_offset + cu_offset,
1086                             debug_info_end, pc, base_address, debug_line_offset,
1087                             cu_name_offset);
1088 }
1089 
1090 // Takes the information from `info` and renders the data located in the
1091 // object file `fd` into `out`.  The format looks like:
1092 //
1093 //   [../path/to/foo.cc:10:40]
1094 //
1095 // which would indicate line 10 column 40 in  ../path/to/foo.cc
SerializeLineNumberInfoToString(int fd,const LineNumberInfo & info,char * out,size_t out_size)1096 void SerializeLineNumberInfoToString(int fd,
1097                                      const LineNumberInfo& info,
1098                                      char* out,
1099                                      size_t out_size) {
1100   size_t out_pos = 0;
1101   if (info.module_filename_offset) {
1102     BufferedDwarfReader reader(fd, info.module_dir_offset);
1103     if (info.module_dir_offset != 0) {
1104       out_pos +=
1105           reader.ReadCString(kMaxOffset, out + out_pos, out_size - out_pos);
1106       out[out_pos - 1] = '/';
1107     }
1108 
1109     reader.set_position(info.module_filename_offset);
1110     out_pos +=
1111         reader.ReadCString(kMaxOffset, out + out_pos, out_size - out_pos);
1112   } else {
1113     out[out_pos++] = '\0';
1114   }
1115 
1116   out[out_pos - 1] = ':';
1117   auto result = std::to_chars(out + out_pos, out + out_size,
1118                               static_cast<intptr_t>(info.line));
1119   if (result.ec != std::errc()) {
1120     out[out_pos - 1] = '\0';
1121     return;
1122   }
1123   out_pos = static_cast<size_t>(result.ptr - out);
1124 
1125   out[out_pos++] = ':';
1126   result = std::to_chars(out + out_pos, out + out_size,
1127                          static_cast<intptr_t>(info.column));
1128   if (result.ec != std::errc()) {
1129     out[out_pos - 1] = '\0';
1130     return;
1131   }
1132   out_pos = static_cast<size_t>(result.ptr - out);
1133 
1134   out[out_pos++] = '\0';
1135 }
1136 
1137 // Reads the Line Number info for a compile unit.
GetLineNumberInfoFromObject(int fd,uint64_t pc,uint64_t cu_offset,uint64_t base_address,char * out,size_t out_size)1138 bool GetLineNumberInfoFromObject(int fd,
1139                                  uint64_t pc,
1140                                  uint64_t cu_offset,
1141                                  uint64_t base_address,
1142                                  char* out,
1143                                  size_t out_size) {
1144   uint64_t cu_name_offset;
1145   uint64_t debug_line_offset;
1146   if (!ReadCompileUnit(fd, pc, cu_offset, base_address, &debug_line_offset,
1147                        &cu_name_offset)) {
1148     return false;
1149   }
1150 
1151   ElfW(Shdr) debug_line;
1152   constexpr static char kDebugLineSectionName[] = ".debug_line";
1153   if (!google::GetSectionHeaderByName(fd, kDebugLineSectionName,
1154                                       sizeof(kDebugLineSectionName),
1155                                       &debug_line)) {
1156     return false;
1157   }
1158 
1159   LineNumberInfo info;
1160   info.pc = pc;
1161   uint64_t line_info_program_offset = debug_line.sh_offset + debug_line_offset;
1162   GetLineNumbersInProgram(fd, &info, base_address, line_info_program_offset,
1163                           cu_name_offset);
1164 
1165   if (info.line == 0) {
1166     // No matching line number or filename found.
1167     return false;
1168   }
1169 
1170   SerializeLineNumberInfoToString(fd, info, out, out_size);
1171 
1172   return true;
1173 }
1174 
1175 struct FrameInfo {
1176   raw_ptr<uint64_t> cu_offset;
1177   uintptr_t pc;
1178 };
1179 
1180 // Returns the number of frames still missing info.
1181 //
1182 // The aranges table is a mapping of ranges to compilation units. Given an array
1183 // of `frame_info`, this finds the compile units for each of the frames doing
1184 // only one pass over the table. It does not preserve the order of `frame_info`.
1185 //
1186 // The main benefit of this function is preserving the single pass through the
1187 // table which is important for performance.
ProcessFlatArangeSet(BufferedDwarfReader * reader,uint64_t next_set,uint8_t address_size,uint64_t base_address,uint64_t cu_offset,FrameInfo * frame_info,size_t num_frames)1188 size_t ProcessFlatArangeSet(BufferedDwarfReader* reader,
1189                             uint64_t next_set,
1190                             uint8_t address_size,
1191                             uint64_t base_address,
1192                             uint64_t cu_offset,
1193                             FrameInfo* frame_info,
1194                             size_t num_frames) {
1195   size_t unsorted_start = 0;
1196   while (unsorted_start < num_frames && reader->position() < next_set) {
1197     uint64_t start;
1198     uint64_t length;
1199     if (!reader->ReadAddress(address_size, start)) {
1200       break;
1201     }
1202     if (!reader->ReadAddress(address_size, length)) {
1203       break;
1204     }
1205     uint64_t end = start + length;
1206     for (size_t i = unsorted_start; i < num_frames; ++i) {
1207       uint64_t module_relative_pc = frame_info[i].pc - base_address;
1208       if (start <= module_relative_pc && module_relative_pc < end) {
1209         *frame_info[i].cu_offset = cu_offset;
1210         if (i != unsorted_start) {
1211           // Move to sorted section.
1212           std::swap(frame_info[i], frame_info[unsorted_start]);
1213         }
1214         unsorted_start++;
1215       }
1216     }
1217   }
1218 
1219   return unsorted_start;
1220 }
1221 
1222 // This is a pre-step that uses the .debug_aranges table to find all the compile
1223 // units for a given set of frames. This allows code to avoid iterating over
1224 // all compile units at a later step in the symbolization process.
PopulateCompileUnitOffsets(int fd,FrameInfo * frame_info,size_t num_frames,uint64_t base_address)1225 void PopulateCompileUnitOffsets(int fd,
1226                                 FrameInfo* frame_info,
1227                                 size_t num_frames,
1228                                 uint64_t base_address) {
1229   ElfW(Shdr) debug_aranges;
1230   constexpr static char kDebugArangesSectionName[] = ".debug_aranges";
1231   if (!google::GetSectionHeaderByName(fd, kDebugArangesSectionName,
1232                                       sizeof(kDebugArangesSectionName),
1233                                       &debug_aranges)) {
1234     return;
1235   }
1236   uint64_t debug_aranges_end = debug_aranges.sh_offset + debug_aranges.sh_size;
1237   uint64_t next_arange_set = kMaxOffset;
1238   size_t unsorted_start = 0;
1239   for (BufferedDwarfReader reader(fd, debug_aranges.sh_offset);
1240        unsorted_start < num_frames && reader.position() < debug_aranges_end;
1241        reader.set_position(next_arange_set)) {
1242     bool is_64bit;
1243     uint64_t length;
1244     uint16_t arange_version;
1245     uint64_t debug_info_offset;
1246     uint8_t address_size;
1247     if (!reader.ReadCommonHeader(is_64bit, length, arange_version,
1248                                  debug_info_offset, address_size,
1249                                  next_arange_set)) {
1250       return;
1251     }
1252 
1253     uint8_t segment_size;
1254     if (!reader.ReadInt8(segment_size)) {
1255       return;
1256     }
1257 
1258     if (segment_size != 0) {
1259       // Only flat namespaces are supported.
1260       return;
1261     }
1262 
1263     // The tuple list is aligned, to a multiple of the tuple-size after the
1264     // section sstart. Because this code only supports flat address spaces, this
1265     // means 2*address_size.
1266     while (((reader.position() - debug_aranges.sh_offset) %
1267             (2 * address_size)) != 0) {
1268       uint8_t dummy;
1269       if (!reader.ReadInt8(dummy)) {
1270         return;
1271       }
1272     }
1273     unsorted_start += ProcessFlatArangeSet(
1274         &reader, next_arange_set, address_size, base_address, debug_info_offset,
1275         &frame_info[unsorted_start], num_frames - unsorted_start);
1276   }
1277 }
1278 
1279 }  // namespace
1280 
GetDwarfSourceLineNumber(const void * pc,uint64_t cu_offset,char * out,size_t out_size)1281 bool GetDwarfSourceLineNumber(const void* pc,
1282                               uint64_t cu_offset,
1283                               char* out,
1284                               size_t out_size) {
1285   uint64_t pc0 = reinterpret_cast<uint64_t>(pc);
1286   uint64_t object_start_address = 0;
1287   uint64_t object_base_address = 0;
1288 
1289   google::FileDescriptor object_fd(google::FileDescriptor(
1290       google::OpenObjectFileContainingPcAndGetStartAddress(
1291           pc0, object_start_address, object_base_address, nullptr, 0)));
1292 
1293   if (!object_fd.get()) {
1294     return false;
1295   }
1296 
1297   if (!GetLineNumberInfoFromObject(object_fd.get(), pc0, cu_offset,
1298                                    object_base_address, out, out_size)) {
1299     return false;
1300   }
1301 
1302   return true;
1303 }
1304 
GetDwarfCompileUnitOffsets(const void * const * trace,uint64_t * cu_offsets,size_t num_frames)1305 void GetDwarfCompileUnitOffsets(const void* const* trace,
1306                                 uint64_t* cu_offsets,
1307                                 size_t num_frames) {
1308   // LINT.IfChange(max_stack_frames)
1309   FrameInfo frame_info[250] = {};
1310   // LINT.ThenChange(stack_trace.h:max_stack_frames)
1311   for (size_t i = 0; i < num_frames; i++) {
1312     // The `cu_offset` also encodes the original sort order.
1313     frame_info[i].cu_offset = &cu_offsets[i];
1314     frame_info[i].pc = reinterpret_cast<uintptr_t>(trace[i]);
1315   }
1316   auto pc_comparator = [](const FrameInfo& lhs, const FrameInfo& rhs) {
1317     return lhs.pc < rhs.pc;
1318   };
1319 
1320   // Use heapsort to avoid recursion in a signal handler.
1321   std::make_heap(&frame_info[0], &frame_info[num_frames - 1], pc_comparator);
1322   std::sort_heap(&frame_info[0], &frame_info[num_frames - 1], pc_comparator);
1323 
1324   // Walk the frame_info one compilation unit at a time.
1325   for (size_t cur_frame = 0; cur_frame < num_frames; ++cur_frame) {
1326     uint64_t object_start_address = 0;
1327     uint64_t object_base_address = 0;
1328     google::FileDescriptor object_fd(google::FileDescriptor(
1329         google::OpenObjectFileContainingPcAndGetStartAddress(
1330             frame_info[cur_frame].pc, object_start_address, object_base_address,
1331             nullptr, 0)));
1332 
1333     // Some stack frames may not have a corresponding object file, e.g. a call
1334     // frame inside the Linux kernel's vdso. Just skip over these stack frames,
1335     // as this is done on a best-effort basis.
1336     if (object_fd.get() < 0) {
1337       continue;
1338     }
1339 
1340     // TODO(https://crbug.com/1335630): Consider exposing the end address so a
1341     // range of frames can be bulk-populated. This was originally implemented,
1342     // but line number symbolization is currently broken by default (and also
1343     // broken in sandboxed processes). The various issues will be addressed
1344     // incrementally in follow-up patches, and the optimization here restored if
1345     // needed.
1346 
1347     PopulateCompileUnitOffsets(object_fd.get(), &frame_info[cur_frame], 1,
1348                                object_base_address);
1349   }
1350 }
1351 
1352 }  // namespace debug
1353 }  // namespace base
1354 
1355 #else  // USE_SYMBOLIZE
1356 
1357 #include <cstring>
1358 
1359 namespace base {
1360 namespace debug {
1361 
GetDwarfSourceLineNumber(const void * pc,uint64_t cu_offset,char * out,size_t out_size)1362 bool GetDwarfSourceLineNumber(const void* pc,
1363                               uint64_t cu_offset,
1364                               char* out,
1365                               size_t out_size) {
1366   return false;
1367 }
1368 
GetDwarfCompileUnitOffsets(const void * const * trace,uint64_t * cu_offsets,size_t num_frames)1369 void GetDwarfCompileUnitOffsets(const void* const* trace,
1370                                 uint64_t* cu_offsets,
1371                                 size_t num_frames) {
1372   // Provide defined values even in the stub.
1373   memset(cu_offsets, 0, sizeof(cu_offsets) * num_frames);
1374 }
1375 
1376 }  // namespace debug
1377 }  // namespace base
1378 
1379 #endif
1380