OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
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 <stdlib.h> | |
6 | |
7 #include "common/dwarf/bytereader.h" | |
8 | |
9 #include "dwarf_reader/dwarf_frame_info_reader.h" | |
10 #include "dwarf_reader/dwarf_info_parser.h" | |
11 #include "dwarf_reader/dwarf_line_parser.h" | |
12 #include "dwarf_reader/dwarf_parser.h" | |
13 #include "dwarf_reader/dwarf_reader.h" | |
14 #include "dwarf_reader/elf_section_reader.h" | |
15 #include "dwarf_reader/parse_state.h" | |
16 | |
17 #include "elf_reader/elf_object.h" | |
18 | |
19 namespace { | |
20 const uint64 kMaxValue = static_cast<uint64>(-1); | |
21 } | |
22 | |
23 namespace dwarf_reader { | |
24 | |
25 DwarfParser::DwarfParser() | |
26 : elf_section_reader_(NULL), | |
27 file_path_(NULL), | |
28 is_initialized_(false) { } | |
29 | |
30 DwarfParser::~DwarfParser() { | |
31 delete elf_section_reader_; | |
32 } | |
33 | |
34 bool DwarfParser::Init(elf_reader::ElfObject *elf_object) { | |
35 if (NULL == elf_object) return false; | |
36 | |
37 file_path_ = elf_object->GetPath(); | |
38 elf_section_reader_ = new ElfSectionReader(); | |
39 | |
40 if (NULL == file_path_ || NULL == elf_section_reader_) return false; | |
41 | |
42 elf_object->Parse(elf_section_reader_); | |
43 is_initialized_ = true; | |
44 | |
45 return is_initialized_; | |
46 } | |
47 | |
48 void DwarfParser::PopulateReader(IDwarfReader *dwarf_reader) const { | |
49 if (is_initialized_) { | |
50 PopulateCompilationUnits(dwarf_reader); | |
51 PopulateCallFrameInfo(dwarf_reader); | |
52 PopulateLocationLists(dwarf_reader); | |
53 PopulateRangeLists(dwarf_reader); | |
54 } | |
55 } | |
56 | |
57 void DwarfParser::PopulateCallFrameInfo(IDwarfReader *dwarf_reader) const { | |
58 SectionInfo debug_frame_section = | |
59 elf_section_reader_->GetSectionInfo(".eh_frame"); | |
60 SectionInfo text_section = elf_section_reader_->GetSectionInfo(".text"); | |
61 | |
62 elf_section_reader_->GetByteReader()->SetTextBase( | |
63 reinterpret_cast<uint64>(text_section.first)); | |
64 elf_section_reader_->GetByteReader()->SetCFIDataBase( | |
65 elf_section_reader_->GetSectionLoadAddress(".eh_frame"), | |
66 debug_frame_section.first); | |
67 | |
68 // Read the call frame information | |
69 dwarf2reader::CallFrameInfo::Reporter reporter(file_path_); | |
70 DwarfFrameInfoReader handler(dwarf_reader); | |
71 dwarf2reader::CallFrameInfo cfi_reader( | |
72 debug_frame_section.first, | |
73 debug_frame_section.second, | |
74 elf_section_reader_->GetByteReader(), | |
75 &handler, | |
76 &reporter, | |
77 true); | |
78 cfi_reader.Start(); | |
79 } | |
80 | |
81 void DwarfParser::PopulateCompilationUnits(IDwarfReader *dwarf_reader) const { | |
82 ParseState parse_state; | |
83 | |
84 SectionInfo debug_info_section = | |
85 elf_section_reader_->GetSectionInfo(".debug_info"); | |
86 SectionInfo debug_line_section = | |
87 elf_section_reader_->GetSectionInfo(".debug_line"); | |
88 | |
89 DwarfInfoParser info_handler(&parse_state, dwarf_reader); | |
90 DwarfLineParser line_handler(&parse_state, dwarf_reader); | |
91 | |
92 uint64 debug_info_length = debug_info_section.second; | |
93 uint64 debug_line_length = debug_line_section.second; | |
94 const char *debug_line_ptr = debug_line_section.first; | |
95 for (uint64 offset = 0; offset < debug_info_length;) { | |
96 dwarf2reader::CompilationUnit compilation_unit_reader( | |
97 elf_section_reader_->sections(), | |
98 offset, | |
99 elf_section_reader_->GetByteReader(), | |
100 &info_handler); | |
101 | |
102 // Process the entire compilation unit; get the offset of the next. | |
103 offset += compilation_unit_reader.Start(); | |
104 | |
105 // Process the matching line information; get the offset of the next. | |
106 dwarf2reader::LineInfo lineInfo(debug_line_ptr, | |
107 debug_line_length, | |
108 elf_section_reader_->GetByteReader(), | |
109 &line_handler); | |
110 | |
111 debug_line_ptr += lineInfo.Start(); | |
112 | |
113 // Pop the end of the compilation unit manually | |
114 dwarf_reader->EndCompilationUnit(parse_state.GetTopStackContext(), | |
115 parse_state.GetTopStackAddress()); | |
116 parse_state.PopStackFrame(); | |
117 } | |
118 } | |
119 | |
120 void DwarfParser::PopulateLocationLists(IDwarfReader *dwarf_reader) const { | |
121 SectionInfo debug_loc_section = | |
122 elf_section_reader_->GetSectionInfo(".debug_loc"); | |
123 | |
124 // Read the location list | |
125 const char* debug_loc_ptr = debug_loc_section.first; | |
126 const char* current = debug_loc_ptr; | |
127 uint64 debug_loc_length = debug_loc_section.second; | |
128 const char* debug_loc_end = debug_loc_ptr + debug_loc_length; | |
129 dwarf2reader::ByteReader* byte_reader = | |
130 elf_section_reader_->GetByteReader(); | |
131 bool is_first = true; | |
132 while (current < debug_loc_end) { | |
133 // Layout of the debug_loc block is: | |
134 // | |
135 // LowPc - address | |
136 // HighPc - address | |
137 // DataLength - ushort (optional) | |
138 // Data - byte[] (optional) | |
139 uint64 offset = current - debug_loc_ptr; | |
140 uint64 low_pc = byte_reader->ReadAddress(current); | |
141 current += byte_reader->AddressSize(); | |
142 uint64 high_pc = byte_reader->ReadAddress(current); | |
143 current += byte_reader->AddressSize(); | |
144 | |
145 size_t data_size = 0; | |
146 const void* data = 0; | |
147 | |
148 if (0 == low_pc && 0 == high_pc) { | |
149 // if low_pc and high_pc are both zero, that signals end of list. | |
150 is_first = true; | |
151 continue; | |
152 } else if (kMaxValue == low_pc) { | |
153 // the location is an absolute address; its value is in high_pc. | |
154 data_size = 4; | |
155 data = &high_pc; | |
156 } else { | |
157 data_size = byte_reader->ReadTwoBytes(current); | |
158 current += 2; | |
159 data = reinterpret_cast<const void *>(current); | |
160 current += data_size; | |
161 } | |
162 dwarf_reader->AddLocListEntry(offset, | |
163 is_first, | |
164 low_pc, | |
165 high_pc, | |
166 data, | |
167 data_size); | |
168 is_first = false; | |
169 } | |
170 } | |
171 | |
172 void DwarfParser::PopulateRangeLists(IDwarfReader *dwarf_reader) const { | |
173 SectionInfo debug_ranges_section = | |
174 elf_section_reader_->GetSectionInfo(".debug_ranges"); | |
175 | |
176 const char *debug_ranges_start = debug_ranges_section.first; | |
177 const char *current = debug_ranges_section.first; | |
178 const char *debug_ranges_end = | |
179 debug_ranges_start + debug_ranges_section.second; | |
180 | |
181 dwarf2reader::ByteReader *byte_reader = | |
182 elf_section_reader_->GetByteReader(); | |
183 | |
184 uint64 offset = 0; | |
185 // When there is no explicit base_address set, we want to populate the range | |
186 // list entry with max value. By convention, this means that the | |
187 // compilation unit's base will serve as the base for these entries. | |
188 uint64 base_address = kMaxValue; | |
189 | |
190 while (current < debug_ranges_end) { | |
191 uint64 low_pc = byte_reader->ReadAddress(current); | |
192 current += byte_reader->AddressSize(); | |
193 uint64 high_pc = byte_reader->ReadAddress(current); | |
194 current += byte_reader->AddressSize(); | |
195 | |
196 if (0 == low_pc && 0 == high_pc) { | |
197 // We are now looking at the start of the next list. | |
198 offset = current - debug_ranges_start; | |
199 base_address = kMaxValue; | |
200 } else if (kMaxValue == low_pc) { | |
201 // This entry is an base address; its value is in high_pc. | |
202 base_address = high_pc; | |
203 } else { | |
204 dwarf_reader->AddRangeListEntry(offset, base_address, low_pc, high_pc); | |
205 } | |
206 } | |
207 } | |
208 | |
209 } // namespace dwarf_parser | |
OLD | NEW |