Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Side by Side Diff: runtime/vm/elfgen.h

Issue 1711163002: Remove more things (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 = &section_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(&section_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 = &section_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(&section_buf_[kShStrtab], str);
377 }
378
379
380 int ElfGen::AddName(const char* str) {
381 return AddString(&section_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(&section_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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698