OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #ifndef VM_ELFGEN_H_ | |
6 #define VM_ELFGEN_H_ | |
7 | |
8 #include "vm/lockers.h" | |
9 #include "vm/os_thread.h" | |
10 | |
11 namespace dart { | |
12 | |
13 // ----------------------------------------------------------------------------- | |
14 // Implementation of ElfGen | |
15 // | |
16 // Specification documents: | |
17 // http://refspecs.freestandards.org | |
18 // | |
19 // ELF generic ABI: | |
20 // http://refspecs.freestandards.org/elf/gabi4+/contents.html | |
21 // ELF processor-specific supplement for X86_64: | |
22 // http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf | |
23 // DWARF 2.0: | |
24 // http://refspecs.freestandards.org/dwarf/dwarf-2.0.0.pdf | |
25 | |
26 // Forward declarations. | |
27 class File; | |
28 | |
29 // ElfGen is used to generate minimal ELF information containing code, symbols, | |
30 // and line numbers for generated code in the dart VM. This information is | |
31 // used in two ways: | |
32 // - it is used to generate in-memory ELF information which is then | |
33 // registered with gdb using the JIT interface. | |
34 // - it is also used to generate a file with the ELF information. This file | |
35 // is not executed, but read by pprof to analyze Dart programs. | |
36 | |
37 class ElfGen { | |
38 public: | |
39 ElfGen(); | |
40 ~ElfGen(); | |
41 | |
42 // Add the code starting at pc. | |
43 void AddCode(uword pc, intptr_t size); | |
44 | |
45 // Add symbol information for a region (includes the start and end symbol), | |
46 // does not add the actual code. | |
47 void AddCodeRegion(const char* name, uword pc, intptr_t size); | |
48 | |
49 // Add specified symbol information, does not add the actual code. | |
50 int AddFunction(const char* name, uword pc, intptr_t size); | |
51 | |
52 // Write out all the Elf information using the specified handle. | |
53 bool WriteToFile(File* handle); | |
54 bool WriteToMemory(DebugInfo::ByteBuffer* region); | |
55 | |
56 // Register this generated section with GDB using the JIT interface. | |
57 static void RegisterSectionWithGDB(const char* name, | |
58 uword entry_point, | |
59 intptr_t size); | |
60 | |
61 // Unregister all generated section from GDB. | |
62 static void UnregisterAllSectionsWithGDB(); | |
63 | |
64 private: | |
65 // ELF helpers | |
66 typedef int (*OutputWriter)(void* handle, | |
67 const DebugInfo::ByteBuffer& section); | |
68 typedef void (*OutputPadder)(void* handle, int padding_size); | |
69 | |
70 int AddString(DebugInfo::ByteBuffer* buf, const char* str); | |
71 int AddSectionName(const char* str); | |
72 int AddName(const char* str); | |
73 void AddELFHeader(int shoff); | |
74 void AddSectionHeader(int section, int offset); | |
75 int PadSection(DebugInfo::ByteBuffer* section, int offset, int alignment); | |
76 bool WriteOutput(void* handle, OutputWriter writer, OutputPadder padder); | |
77 | |
78 uword text_vma_; // text section vma | |
79 intptr_t text_size_; // text section size | |
80 int text_padding_; // padding preceding text section | |
81 | |
82 static const int kNumSections = 5; // we generate 5 sections | |
83 int section_name_[kNumSections]; // array of section name indices | |
84 DebugInfo::ByteBuffer section_buf_[kNumSections]; // array of section buffers | |
85 DebugInfo::ByteBuffer header_; // ELF header buffer | |
86 DebugInfo::ByteBuffer sheaders_; // section header table buffer | |
87 DebugInfo::ByteBuffer lineprog_; // line statement program, part of | |
88 // '.debug_line' section | |
89 | |
90 // current state of the DWARF line info generator | |
91 uintptr_t cur_addr_; // current pc | |
92 int map_offset_; | |
93 uword map_begin_; | |
94 uword map_end_; | |
95 | |
96 Mutex lock_; | |
97 }; | |
98 | |
99 | |
100 enum { | |
101 // Various constant sizes for ELF files. | |
102 kAddrSize = sizeof(uword), | |
103 kPageSize = 4*1024, // Memory mapping page size. | |
104 kTextAlign = 16, | |
105 kELFHeaderSize = 40 + 3*kAddrSize, | |
106 kProgramHeaderEntrySize = 8 + 6*kAddrSize, | |
107 kSectionHeaderEntrySize = 16 + 6*kAddrSize, | |
108 kSymbolSize = 8 + 2*kAddrSize, | |
109 | |
110 // Our own layout of sections. | |
111 kUndef = 0, // Undefined section. | |
112 kText, // Text section. | |
113 kShStrtab, // Section header string table. | |
114 kStrtab, // String table. | |
115 kSymtab, // Symbol table. | |
116 kNumSections, // Num of section header entries in section header table. | |
117 | |
118 // Various ELF constants. | |
119 kELFCLASS32 = 1, | |
120 kELFCLASS64 = 2, | |
121 kELFDATA2LSB = 1, | |
122 kELFDATA2MSB = 2, | |
123 kEM_386 = 3, | |
124 kEM_MIPS = 8, | |
125 kEM_ARM = 40, | |
126 kEM_X86_64 = 62, | |
127 kEV_CURRENT = 1, | |
128 kET_EXEC = 2, // not used | |
129 kET_DYN = 3, | |
130 kSHT_PROGBITS = 1, | |
131 kSHT_SYMTAB = 2, | |
132 kSHT_STRTAB = 3, | |
133 kSHF_WRITE = 1, // not used | |
134 kSHF_ALLOC = 2, | |
135 kSHF_EXECINSTR = 4, | |
136 kSTB_LOCAL = 0, | |
137 kSTB_EXPORTED = 1, | |
138 kSTT_FUNC = 2, | |
139 }; | |
140 | |
141 | |
142 // ELF and DWARF constants. | |
143 static const char* kEI_MAG0_MAG3 = "\177ELF"; | |
144 static const uint8_t kSpecialOpcodeLengths[] = { 0, 1, 1, 1, 1, 0, 0, 0, 1 }; | |
145 | |
146 | |
147 // Section attributes. | |
148 // The field names correspond to the field names of Elf32_Shdr and Elf64_Shdr. | |
149 static const struct { | |
150 // Section header index (only used to check correct section order). | |
151 int shndx; | |
152 const char* name; // sh_name will be the index of name inserted in shstrtab. | |
153 int sh_type; | |
154 int sh_flags; | |
155 int sh_link; | |
156 int sh_addralign; | |
157 int sh_entsize; | |
158 } section_attr[kNumSections + 1] = { | |
159 { kUndef, "", 0, 0, | |
160 0, 0, 0 }, | |
161 { kText, ".text", kSHT_PROGBITS, kSHF_ALLOC|kSHF_EXECINSTR, | |
162 0, kTextAlign, 0 }, | |
163 { kShStrtab, ".shstrtab", kSHT_STRTAB, 0, | |
164 0, 1, 0 }, | |
165 { kStrtab, ".strtab", kSHT_STRTAB, 0, | |
166 0, 1, 0 }, | |
167 { kSymtab, ".symtab", kSHT_SYMTAB, 0, | |
168 kStrtab, kAddrSize, kSymbolSize }, | |
169 // Sentinel to pad the last section | |
170 // for proper alignment of section header table. | |
171 { 0, "", 0, 0, | |
172 0, kAddrSize, 0 } | |
173 }; | |
174 | |
175 | |
176 // Convenience function aligning an integer. | |
177 static inline uintptr_t Align(uintptr_t x, intptr_t size) { | |
178 // size is a power of 2 | |
179 ASSERT((size & (size-1)) == 0); | |
180 return (x + (size-1)) & ~(size-1); | |
181 } | |
182 | |
183 | |
184 // Convenience function writing a single byte to a ByteBuffer. | |
185 static inline void WriteByte(DebugInfo::ByteBuffer* buf, uint8_t byte) { | |
186 buf->Add(byte); | |
187 } | |
188 | |
189 | |
190 // Convenience function writing an unsigned native word to a ByteBuffer. | |
191 // The word is 32-bit wide in 32-bit mode and 64-bit wide in 64-bit mode. | |
192 static inline void WriteWord(DebugInfo::ByteBuffer* buf, uword word) { | |
193 uint8_t* p = reinterpret_cast<uint8_t*>(&word); | |
194 for (size_t i = 0; i < sizeof(word); i++) { | |
195 buf->Add(p[i]); | |
196 } | |
197 } | |
198 | |
199 static inline void WriteInt(DebugInfo::ByteBuffer* buf, int word) { | |
200 uint8_t* p = reinterpret_cast<uint8_t*>(&word); | |
201 for (size_t i = 0; i < sizeof(word); i++) { | |
202 buf->Add(p[i]); | |
203 } | |
204 } | |
205 | |
206 static inline void WriteShort(DebugInfo::ByteBuffer* buf, uint16_t word) { | |
207 uint8_t* p = reinterpret_cast<uint8_t*>(&word); | |
208 for (size_t i = 0; i < sizeof(word); i++) { | |
209 buf->Add(p[i]); | |
210 } | |
211 } | |
212 | |
213 static inline void WriteString(DebugInfo::ByteBuffer* buf, const char* str) { | |
214 for (size_t i = 0; i < strlen(str); i++) { | |
215 buf->Add(static_cast<uint8_t>(str[i])); | |
216 } | |
217 } | |
218 | |
219 static inline void Write(DebugInfo::ByteBuffer* buf, | |
220 const void* mem, | |
221 int length) { | |
222 const uint8_t* p = reinterpret_cast<const uint8_t*>(mem); | |
223 for (int i = 0; i < length; i++) { | |
224 buf->Add(p[i]); | |
225 } | |
226 } | |
227 | |
228 | |
229 // Write given section to file and return written size. | |
230 static int WriteSectionToFile(void* handle, | |
231 const DebugInfo::ByteBuffer& section) { | |
232 #if 0 | |
233 File* fp = reinterpret_cast<File*>(handle); | |
234 int size = section.size(); | |
235 fp->WriteFully(section.data(), size); | |
236 return size; | |
237 #else | |
238 return 0; | |
239 #endif | |
240 } | |
241 | |
242 | |
243 // Pad output file to specified padding size. | |
244 static void PadFile(void* handle, int padding_size) { | |
245 #if 0 | |
246 File* fp = reinterpret_cast<File*>(handle); | |
247 for (int i = 0; i < padding_size; i++) { | |
248 fp->WriteFully("", 1); | |
249 } | |
250 #endif | |
251 } | |
252 | |
253 | |
254 // Write given section to specified memory region and return written size. | |
255 static int WriteSectionToMemory(void* handle, | |
256 const DebugInfo::ByteBuffer& section) { | |
257 DebugInfo::ByteBuffer* buffer = | |
258 reinterpret_cast<DebugInfo::ByteBuffer*>(handle); | |
259 int size = section.size(); | |
260 for (int i = 0; i < size; i++) { | |
261 buffer->Add(static_cast<uint8_t>(section.data()[i])); | |
262 } | |
263 return size; | |
264 } | |
265 | |
266 | |
267 // Pad memory to specified padding size. | |
268 static void PadMemory(void* handle, int padding_size) { | |
269 DebugInfo::ByteBuffer* buffer = | |
270 reinterpret_cast<DebugInfo::ByteBuffer*>(handle); | |
271 for (int i = 0; i < padding_size; i++) { | |
272 buffer->Add(static_cast<uint8_t>(0)); | |
273 } | |
274 } | |
275 | |
276 | |
277 // Constructor | |
278 ElfGen::ElfGen() | |
279 : text_vma_(0), text_size_(0), text_padding_(0), map_offset_(0), lock_() { | |
280 for (int i = 0; i < kNumSections; i++) { | |
281 ASSERT(section_attr[i].shndx == i); // Verify layout of sections. | |
282 section_name_[i] = AddSectionName(section_attr[i].name); | |
283 } | |
284 // Section header string table always starts with an empty string, which is | |
285 // the name of the kUndef section. | |
286 ASSERT((section_attr[0].name[0] == '\0') && (section_name_[0] == 0)); | |
287 | |
288 // String table always starts with an empty string. | |
289 AddName(""); | |
290 ASSERT(section_buf_[kStrtab].size() == 1); | |
291 | |
292 // Symbol at index 0 in symtab is always STN_UNDEF (all zero): | |
293 DebugInfo::ByteBuffer* symtab = §ion_buf_[kSymtab]; | |
294 while (symtab->size() < kSymbolSize) { | |
295 WriteInt(symtab, 0); | |
296 } | |
297 ASSERT(symtab->size() == kSymbolSize); | |
298 } | |
299 | |
300 | |
301 // Destructor | |
302 ElfGen::~ElfGen() { | |
303 } | |
304 | |
305 | |
306 void ElfGen::AddCode(uword pc, intptr_t size) { | |
307 MutexLocker ml(&lock_); | |
308 text_vma_ = pc; | |
309 text_size_ = size; | |
310 // We pad the text section in the file to align absolute code addresses with | |
311 // corresponding file offsets as if the code had been loaded by memory | |
312 // mapping. | |
313 if (text_vma_ % kPageSize < kELFHeaderSize) { | |
314 text_padding_ = text_vma_ % kPageSize + kPageSize - kELFHeaderSize; | |
315 } else { | |
316 text_padding_ = text_vma_ % kPageSize - kELFHeaderSize; | |
317 } | |
318 | |
319 Write(§ion_buf_[kText], reinterpret_cast<void*>(pc), size); | |
320 // map_offset is the file offset of the first mapped page. | |
321 map_offset_ = (kELFHeaderSize + text_padding_)/kPageSize*kPageSize; | |
322 map_begin_ = Align(text_vma_ - kPageSize + 1, kPageSize); | |
323 map_end_ = Align(text_vma_ + size, kPageSize); | |
324 } | |
325 | |
326 | |
327 void ElfGen::AddCodeRegion(const char* name, uword pc, intptr_t size) { | |
328 MutexLocker ml(&lock_); | |
329 AddFunction(name, pc, size); | |
330 char end_name[256]; | |
331 OS::SNPrint(end_name, sizeof(end_name), "%s_end", name); | |
332 AddFunction(end_name, pc + size, 0); | |
333 } | |
334 | |
335 | |
336 int ElfGen::AddFunction(const char* name, uword pc, intptr_t size) { | |
337 ASSERT(text_vma_ != 0); // code must have been added | |
338 DebugInfo::ByteBuffer* symtab = §ion_buf_[kSymtab]; | |
339 const int beg = symtab->size(); | |
340 WriteInt(symtab, AddName(name)); // st_name | |
341 #if defined(ARCH_IS_64_BIT) | |
342 WriteShort(symtab, (kSTB_LOCAL << 4) + kSTT_FUNC); // st_info + (st_other<<8) | |
343 WriteShort(symtab, kText); // st_shndx | |
344 #endif | |
345 WriteWord(symtab, pc); // st_value | |
346 WriteWord(symtab, size); // st_size | |
347 #if defined(ARCH_IS_32_BIT) | |
348 // st_info + (st_other<<8) | |
349 WriteShort(symtab, (kSTB_EXPORTED << 4) + kSTT_FUNC); | |
350 WriteShort(symtab, kText); // st_shndx | |
351 #endif | |
352 ASSERT(symtab->size() - beg == kSymbolSize); | |
353 return beg / kSymbolSize; // symbol index in symtab | |
354 } | |
355 | |
356 | |
357 bool ElfGen::WriteToFile(File* handle) { | |
358 return WriteOutput(handle, WriteSectionToFile, PadFile); | |
359 } | |
360 | |
361 | |
362 bool ElfGen::WriteToMemory(DebugInfo::ByteBuffer* region) { | |
363 return WriteOutput(region, WriteSectionToMemory, PadMemory); | |
364 } | |
365 | |
366 | |
367 int ElfGen::AddString(DebugInfo::ByteBuffer* buf, const char* str) { | |
368 const int str_index = buf->size(); | |
369 WriteString(buf, str); | |
370 WriteByte(buf, 0); // terminating '\0' | |
371 return str_index; | |
372 } | |
373 | |
374 | |
375 int ElfGen::AddSectionName(const char* str) { | |
376 return AddString(§ion_buf_[kShStrtab], str); | |
377 } | |
378 | |
379 | |
380 int ElfGen::AddName(const char* str) { | |
381 return AddString(§ion_buf_[kStrtab], str); | |
382 } | |
383 | |
384 | |
385 void ElfGen::AddELFHeader(int shoff) { | |
386 ASSERT(text_vma_ != 0); // Code must have been added. | |
387 Write(&header_, kEI_MAG0_MAG3, 4); // EI_MAG0..EI_MAG3 | |
388 #if defined(ARCH_IS_32_BIT) | |
389 WriteByte(&header_, kELFCLASS32); // EI_CLASS | |
390 #elif defined(ARCH_IS_64_BIT) | |
391 WriteByte(&header_, kELFCLASS64); // EI_CLASS | |
392 #else | |
393 #error Unknown architecture. | |
394 #endif | |
395 WriteByte(&header_, kELFDATA2LSB); // EI_DATA | |
396 WriteByte(&header_, kEV_CURRENT); // EI_VERSION | |
397 WriteByte(&header_, 0); // EI_PAD | |
398 WriteInt(&header_, 0); // EI_PAD | |
399 WriteInt(&header_, 0); // EI_PAD | |
400 WriteShort(&header_, kET_DYN); // e_type, fake a shared object. | |
401 #if defined(TARGET_ARCH_IA32) | |
402 WriteShort(&header_, kEM_386); // e_machine | |
403 #elif defined(TARGET_ARCH_X64) | |
404 WriteShort(&header_, kEM_X86_64); // e_machine | |
405 #elif defined(TARGET_ARCH_ARM) | |
406 WriteShort(&header_, kEM_ARM); // e_machine | |
407 #elif defined(TARGET_ARCH_ARM64) | |
408 // TODO(zra): Find the right ARM64 constant. | |
409 WriteShort(&header_, kEM_ARM); // e_machine | |
410 #elif defined(TARGET_ARCH_MIPS) | |
411 WriteShort(&header_, kEM_MIPS); // e_machine | |
412 #else | |
413 #error Unknown architecture. | |
414 #endif | |
415 WriteInt(&header_, kEV_CURRENT); // e_version | |
416 WriteWord(&header_, 0); // e_entry: none | |
417 WriteWord(&header_, 0); // e_phoff: no program header table. | |
418 WriteWord(&header_, shoff); // e_shoff: section header table offset. | |
419 WriteInt(&header_, 0); // e_flags: no flags. | |
420 WriteShort(&header_, kELFHeaderSize); // e_ehsize: header size. | |
421 WriteShort(&header_, kProgramHeaderEntrySize); // e_phentsize | |
422 WriteShort(&header_, 0); // e_phnum: no entries program header table. | |
423 WriteShort(&header_, kSectionHeaderEntrySize); // e_shentsize | |
424 // e_shnum: number of section header entries. | |
425 WriteShort(&header_, kNumSections); | |
426 WriteShort(&header_, kShStrtab); // e_shstrndx: index of shstrtab. | |
427 ASSERT(header_.size() == kELFHeaderSize); | |
428 } | |
429 | |
430 | |
431 void ElfGen::AddSectionHeader(int section, int offset) { | |
432 WriteInt(&sheaders_, section_name_[section]); | |
433 WriteInt(&sheaders_, section_attr[section].sh_type); | |
434 WriteWord(&sheaders_, section_attr[section].sh_flags); | |
435 // sh_addr: abs addr | |
436 WriteWord(&sheaders_, (section == kText) ? text_vma_ : 0); | |
437 WriteWord(&sheaders_, offset); // sh_offset: section file offset. | |
438 WriteWord(&sheaders_, section_buf_[section].size()); | |
439 WriteInt(&sheaders_, section_attr[section].sh_link); | |
440 WriteInt(&sheaders_, 0); | |
441 WriteWord(&sheaders_, section_attr[section].sh_addralign); | |
442 WriteWord(&sheaders_, section_attr[section].sh_entsize); | |
443 ASSERT(sheaders_.size() == kSectionHeaderEntrySize * (section + 1)); | |
444 } | |
445 | |
446 | |
447 // Pads the given section with zero bytes for the given aligment, assuming the | |
448 // section starts at given file offset; returns file offset after padded | |
449 // section. | |
450 int ElfGen::PadSection(DebugInfo::ByteBuffer* section, | |
451 int offset, | |
452 int alignment) { | |
453 offset += section->size(); | |
454 int aligned_offset = Align(offset, alignment); | |
455 while (offset++ < aligned_offset) { | |
456 WriteByte(section, 0); // one byte padding. | |
457 } | |
458 return aligned_offset; | |
459 } | |
460 | |
461 | |
462 bool ElfGen::WriteOutput(void* handle, | |
463 OutputWriter writer, | |
464 OutputPadder padder) { | |
465 if (handle == NULL || writer == NULL || padder == NULL) { | |
466 return false; | |
467 } | |
468 | |
469 // Align all sections before writing the ELF header in order to calculate the | |
470 // file offset of the section header table, which is needed in the ELF header. | |
471 // Pad each section as required by the aligment constraint of the immediately | |
472 // following section, except the ELF header section, which requires special | |
473 // padding (text_padding_) to align the text_ section. | |
474 int offset = kELFHeaderSize + text_padding_; | |
475 for (int i = kText; i < kNumSections; i++) { | |
476 offset = PadSection(§ion_buf_[i], | |
477 offset, | |
478 section_attr[i+1].sh_addralign); | |
479 } | |
480 | |
481 const int shoff = offset; // Section header table offset. | |
482 | |
483 // Write elf header. | |
484 AddELFHeader(shoff); | |
485 offset = (*writer)(handle, header_); | |
486 | |
487 // Pad file before writing text section in order to align vma with file | |
488 // offset. | |
489 (*padder)(handle, text_padding_); | |
490 | |
491 offset += text_padding_; | |
492 ASSERT((text_vma_ - offset) % kPageSize == 0); | |
493 | |
494 // Section header at index 0 in section header table is always SHN_UNDEF: | |
495 for (int i = 0; i < kNumSections; i++) { | |
496 AddSectionHeader(i, offset); | |
497 offset += (*writer)(handle, section_buf_[i]); | |
498 } | |
499 // Write section header table. | |
500 ASSERT(offset == shoff); | |
501 offset += (*writer)(handle, sheaders_); | |
502 ASSERT(offset == shoff + kNumSections * kSectionHeaderEntrySize); | |
503 | |
504 return true; | |
505 } | |
506 | |
507 } // namespace dart | |
508 | |
509 #endif // VM_ELFGEN_H_ | |
OLD | NEW |