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

Side by Side Diff: runtime/vm/debuginfo_android.cc

Issue 10827327: Add GDB JIT support back into Android build. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/debuginfo.h" 5 #include "vm/debuginfo.h"
6 6
7 #include "platform/utils.h"
8 #include "vm/gdbjit_android.h"
9 #include "vm/os.h"
10 #include "vm/thread.h"
7 11
8 namespace dart { 12 namespace dart {
9 13
14 // -----------------------------------------------------------------------------
cshapiro 2012/08/14 22:18:26 Can you move this into an elfgen.h which is includ
jackpal 2012/08/15 01:29:48 Done.
15 // Implementation of ElfGen
16 //
17 // Specification documents:
18 // http://refspecs.freestandards.org
19 //
20 // ELF generic ABI:
21 // http://refspecs.freestandards.org/elf/gabi4+/contents.html
22 // ELF processor-specific supplement for X86_64:
23 // http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf
24 // DWARF 2.0:
25 // http://refspecs.freestandards.org/dwarf/dwarf-2.0.0.pdf
26
27 // Forward declarations.
28 class File;
29
30 // ElfGen is used to generate minimal ELF information containing code, symbols,
31 // and line numbers for generated code in the dart VM. This information is
32 // used in two ways:
33 // - it is used to generate in-memory ELF information which is then
34 // registered with gdb using the JIT interface.
35 // - it is also used to generate a file with the ELF information. This file
36 // is not executed, but read by pprof to analyze Dart programs.
37
38 class ElfGen {
39 public:
40 ElfGen();
41 ~ElfGen();
42
43 // Add the code starting at pc.
44 void AddCode(uword pc, intptr_t size);
45
46 // Add symbol information for a region (includes the start and end symbol),
47 // does not add the actual code.
48 void AddCodeRegion(const char* name, uword pc, intptr_t size);
49
50 // Add specified symbol information, does not add the actual code.
51 int AddFunction(const char* name, uword pc, intptr_t size);
52
53 // Write out all the Elf information using the specified handle.
54 bool WriteToFile(File* handle);
55 bool WriteToMemory(DebugInfo::ByteBuffer* region);
56
57 // Register this generated section with GDB using the JIT interface.
58 static void RegisterSectionWithGDB(const char* name,
59 uword entry_point,
60 intptr_t size);
61
62 // Unregister all generated section from GDB.
63 static void UnregisterAllSectionsWithGDB();
64
65 private:
66 // ELF helpers
67 typedef int (*OutputWriter)(void* handle,
68 const DebugInfo::ByteBuffer& section);
69 typedef void (*OutputPadder)(void* handle, int padding_size);
70
71 int AddString(DebugInfo::ByteBuffer* buf, const char* str);
72 int AddSectionName(const char* str);
73 int AddName(const char* str);
74 void AddELFHeader(int shoff);
75 void AddSectionHeader(int section, int offset);
76 int PadSection(DebugInfo::ByteBuffer* section, int offset, int alignment);
77 bool WriteOutput(void* handle, OutputWriter writer, OutputPadder padder);
78
79 uword text_vma_; // text section vma
80 intptr_t text_size_; // text section size
81 int text_padding_; // padding preceding text section
82
83 static const int kNumSections = 5; // we generate 5 sections
84 int section_name_[kNumSections]; // array of section name indices
85 DebugInfo::ByteBuffer section_buf_[kNumSections]; // array of section buffers
86 DebugInfo::ByteBuffer header_; // ELF header buffer
87 DebugInfo::ByteBuffer sheaders_; // section header table buffer
88 DebugInfo::ByteBuffer lineprog_; // line statement program, part of
89 // '.debug_line' section
90
91 // current state of the DWARF line info generator
92 uintptr_t cur_addr_; // current pc
93 int map_offset_;
94 uword map_begin_;
95 uword map_end_;
96
97 Mutex lock_;
98 };
99
100
101 enum {
102 // Various constant sizes for ELF files.
103 kAddrSize = sizeof(uword),
104 kPageSize = 4*1024, // Memory mapping page size.
105 kTextAlign = 16,
106 kELFHeaderSize = 40 + 3*kAddrSize,
107 kProgramHeaderEntrySize = 8 + 6*kAddrSize,
108 kSectionHeaderEntrySize = 16 + 6*kAddrSize,
109 kSymbolSize = 8 + 2*kAddrSize,
110
111 // Our own layout of sections.
112 kUndef = 0, // Undefined section.
113 kText, // Text section.
114 kShStrtab, // Section header string table.
115 kStrtab, // String table.
116 kSymtab, // Symbol table.
117 kNumSections, // Num of section header entries in section header table.
118
119 // Various ELF constants.
120 kELFCLASS32 = 1,
121 kELFCLASS64 = 2,
122 kELFDATA2LSB = 1,
123 kELFDATA2MSB = 2,
124 kEM_386 = 3,
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(TARGET_ARCH_X64)
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(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
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(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
389 WriteByte(&header_, kELFCLASS32); // EI_CLASS
390 #elif defined(TARGET_ARCH_X64)
391 WriteByte(&header_, kELFCLASS64); // EI_CLASS
392 #endif
393 WriteByte(&header_, kELFDATA2LSB); // EI_DATA
394 WriteByte(&header_, kEV_CURRENT); // EI_VERSION
395 WriteByte(&header_, 0); // EI_PAD
396 WriteInt(&header_, 0); // EI_PAD
397 WriteInt(&header_, 0); // EI_PAD
398 WriteShort(&header_, kET_DYN); // e_type, fake a shared object.
399 #if defined(TARGET_ARCH_IA32)
400 WriteShort(&header_, kEM_386); // e_machine
401 #elif defined(TARGET_ARCH_X64)
402 WriteShort(&header_, kEM_X86_64); // e_machine
403 #elif defined(TARGET_ARCH_ARM)
404 WriteShort(&header_, kEM_ARM); // e_machine
405 #endif
406 WriteInt(&header_, kEV_CURRENT); // e_version
407 WriteWord(&header_, 0); // e_entry: none
408 WriteWord(&header_, 0); // e_phoff: no program header table.
409 WriteWord(&header_, shoff); // e_shoff: section header table offset.
410 WriteInt(&header_, 0); // e_flags: no flags.
411 WriteShort(&header_, kELFHeaderSize); // e_ehsize: header size.
412 WriteShort(&header_, kProgramHeaderEntrySize); // e_phentsize
413 WriteShort(&header_, 0); // e_phnum: no entries program header table.
414 WriteShort(&header_, kSectionHeaderEntrySize); // e_shentsize
415 // e_shnum: number of section header entries.
416 WriteShort(&header_, kNumSections);
417 WriteShort(&header_, kShStrtab); // e_shstrndx: index of shstrtab.
418 ASSERT(header_.size() == kELFHeaderSize);
419 }
420
421
422 void ElfGen::AddSectionHeader(int section, int offset) {
423 WriteInt(&sheaders_, section_name_[section]);
424 WriteInt(&sheaders_, section_attr[section].sh_type);
425 WriteWord(&sheaders_, section_attr[section].sh_flags);
426 // sh_addr: abs addr
427 WriteWord(&sheaders_, (section == kText) ? text_vma_ : 0);
428 WriteWord(&sheaders_, offset); // sh_offset: section file offset.
429 WriteWord(&sheaders_, section_buf_[section].size());
430 WriteInt(&sheaders_, section_attr[section].sh_link);
431 WriteInt(&sheaders_, 0);
432 WriteWord(&sheaders_, section_attr[section].sh_addralign);
433 WriteWord(&sheaders_, section_attr[section].sh_entsize);
434 ASSERT(sheaders_.size() == kSectionHeaderEntrySize * (section + 1));
435 }
436
437
438 // Pads the given section with zero bytes for the given aligment, assuming the
439 // section starts at given file offset; returns file offset after padded
440 // section.
441 int ElfGen::PadSection(DebugInfo::ByteBuffer* section,
442 int offset,
443 int alignment) {
444 offset += section->size();
445 int aligned_offset = Align(offset, alignment);
446 while (offset++ < aligned_offset) {
447 WriteByte(section, 0); // one byte padding.
448 }
449 return aligned_offset;
450 }
451
452
453 bool ElfGen::WriteOutput(void* handle,
454 OutputWriter writer,
455 OutputPadder padder) {
456 if (handle == NULL || writer == NULL || padder == NULL) {
457 return false;
458 }
459
460 // Align all sections before writing the ELF header in order to calculate the
461 // file offset of the section header table, which is needed in the ELF header.
462 // Pad each section as required by the aligment constraint of the immediately
463 // following section, except the ELF header section, which requires special
464 // padding (text_padding_) to align the text_ section.
465 int offset = kELFHeaderSize + text_padding_;
466 for (int i = kText; i < kNumSections; i++) {
467 offset = PadSection(&section_buf_[i],
468 offset,
469 section_attr[i+1].sh_addralign);
470 }
471
472 const int shoff = offset; // Section header table offset.
473
474 // Write elf header.
475 AddELFHeader(shoff);
476 offset = (*writer)(handle, header_);
477
478 // Pad file before writing text section in order to align vma with file
479 // offset.
480 (*padder)(handle, text_padding_);
481
482 offset += text_padding_;
483 ASSERT((text_vma_ - offset) % kPageSize == 0);
484
485 // Section header at index 0 in section header table is always SHN_UNDEF:
486 for (int i = 0; i < kNumSections; i++) {
487 AddSectionHeader(i, offset);
488 offset += (*writer)(handle, section_buf_[i]);
489 }
490 // Write section header table.
491 ASSERT(offset == shoff);
492 offset += (*writer)(handle, sheaders_);
493 ASSERT(offset == shoff + kNumSections * kSectionHeaderEntrySize);
494
495 return true;
496 }
497
498
10 DebugInfo::DebugInfo() { 499 DebugInfo::DebugInfo() {
11 handle_ = NULL; 500 handle_ = reinterpret_cast<void*>(new ElfGen());
501 ASSERT(handle_ != NULL);
12 } 502 }
13 503
14 504
15 DebugInfo::~DebugInfo() { 505 DebugInfo::~DebugInfo() {
506 ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
507 delete elf_gen;
16 } 508 }
17 509
18 510
19 void DebugInfo::AddCode(uword pc, intptr_t size) { 511 void DebugInfo::AddCode(uword pc, intptr_t size) {
20 // Nothing to do as there is no support for this on Android. 512 ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
513 elf_gen->AddCode(pc, size);
21 } 514 }
22 515
23 516
24 void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) { 517 void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) {
25 // Nothing to do as there is no support for this on Android. 518 ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
519 elf_gen->AddCodeRegion(name, pc, size);
26 } 520 }
27 521
28 522
29 bool DebugInfo::WriteToMemory(ByteBuffer* region) { 523 bool DebugInfo::WriteToMemory(ByteBuffer* region) {
30 // Nothing to do as there is no support for this on Android. 524 ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
31 return false; 525 return elf_gen->WriteToMemory(region);
32 } 526 }
33 527
34 528
35 DebugInfo* DebugInfo::NewGenerator() { 529 DebugInfo* DebugInfo::NewGenerator() {
36 return new DebugInfo(); 530 return new DebugInfo();
37 } 531 }
38 532
39 533
40 void DebugInfo::RegisterSection(const char* name, 534 void DebugInfo::RegisterSection(const char* name,
41 uword entry_point, 535 uword entry_point,
42 intptr_t size) { 536 intptr_t size) {
43 // Nothing to do as there is no support for this on Android. 537 ElfGen* elf_section = new ElfGen();
538 ASSERT(elf_section != NULL);
539 elf_section->AddCode(entry_point, size);
540 elf_section->AddCodeRegion(name, entry_point, size);
541
542 ByteBuffer* dynamic_region = new ByteBuffer();
543 ASSERT(dynamic_region != NULL);
544
545 elf_section->WriteToMemory(dynamic_region);
546
547 ::addDynamicSection(reinterpret_cast<const char*>(dynamic_region->data()),
548 dynamic_region->size());
549 dynamic_region->set_data(NULL);
550 delete dynamic_region;
551 delete elf_section;
44 } 552 }
45 553
46 554
47 void DebugInfo::UnregisterAllSections() { 555 void DebugInfo::UnregisterAllSections() {
48 // Nothing to do as there is no support for this on Android. 556 ::deleteDynamicSections();
49 } 557 }
50 558
51 } // namespace dart 559 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698