OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2010 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #ifdef ENABLE_GDBJIT_INTERFACE | |
29 #include "gdbjit.h" | |
30 | |
31 #include "bootstrapper.h" | |
32 #include "compiler.h" | |
33 #include "global-handles.h" | |
34 #include "messages.h" | |
35 #include "natives.h" | |
36 | |
37 namespace v8 { | |
38 namespace internal { | |
39 | |
40 class ELF; | |
41 | |
42 class Writer BASE_EMBEDDED { | |
43 public: | |
44 explicit Writer(ELF* elf) | |
45 : elf_(elf), | |
46 position_(0), | |
47 capacity_(1024), | |
48 buffer_(reinterpret_cast<byte*>(malloc(capacity_))) { | |
49 } | |
50 | |
51 ~Writer() { | |
52 free(buffer_); | |
53 } | |
54 | |
55 uintptr_t position() const { | |
56 return position_; | |
57 } | |
58 | |
59 template<typename T> | |
60 class Slot { | |
61 public: | |
62 Slot(Writer* w, uintptr_t offset) : w_(w), offset_(offset) { } | |
63 | |
64 T* operator-> () { | |
65 return w_->RawSlotAt<T>(offset_); | |
66 } | |
67 | |
68 void set(const T& value) { | |
69 *w_->RawSlotAt<T>(offset_) = value; | |
70 } | |
71 | |
72 Slot<T> at(int i) { | |
73 return Slot<T>(w_, offset_ + sizeof(T) * i); | |
74 } | |
75 | |
76 private: | |
77 Writer* w_; | |
78 uintptr_t offset_; | |
79 }; | |
80 | |
81 template<typename T> | |
82 void Write(const T& val) { | |
83 Ensure(position_ + sizeof(T)); | |
84 *RawSlotAt<T>(position_) = val; | |
85 position_ += sizeof(T); | |
86 } | |
87 | |
88 template<typename T> | |
89 Slot<T> SlotAt(uintptr_t offset) { | |
90 Ensure(offset + sizeof(T)); | |
91 return Slot<T>(this, offset); | |
92 } | |
93 | |
94 template<typename T> | |
95 Slot<T> SlotHere() { | |
Erik Corry
2011/01/04 14:21:48
The name should reflect the fact that this functio
Vyacheslav Egorov (Chromium)
2011/01/18 16:10:42
Done.
| |
96 return SlotsHere<T>(1); | |
97 } | |
98 | |
99 template<typename T> | |
100 Slot<T> SlotsHere(uint32_t count) { | |
101 uintptr_t slot_position = position_; | |
102 Ensure(position_ += sizeof(T) * count); | |
Erik Corry
2011/01/04 14:21:48
no no no no
Vyacheslav Egorov (Chromium)
2011/01/18 16:10:42
Done.
| |
103 return SlotAt<T>(slot_position); | |
104 } | |
105 | |
106 void Ensure(uintptr_t pos) { | |
107 if (capacity_ < pos) { | |
108 while (capacity_ < pos) capacity_ *= 2; | |
109 buffer_ = reinterpret_cast<byte*>(realloc(buffer_, capacity_)); | |
110 } | |
111 } | |
112 | |
113 ELF* elf() { return elf_; } | |
114 | |
115 byte* buffer() { return buffer_; } | |
116 | |
117 void Align(uintptr_t align) { | |
118 uintptr_t delta = position_ % align; | |
119 if (delta == 0) return; | |
120 uintptr_t padding = align - delta; | |
121 Ensure(position_ += padding); | |
122 ASSERT((position_ % align) == 0); | |
123 } | |
124 | |
125 void WriteULEB128(uintptr_t value) { | |
126 do { | |
127 uint8_t byte = value & 0x7F; | |
128 value >>= 7; | |
129 if (value != 0) byte |= 0x80; | |
130 Write<uint8_t>(byte); | |
131 } while (value != 0); | |
132 } | |
133 | |
134 void WriteSLEB128(intptr_t value) { | |
135 bool more = true; | |
136 while (more) { | |
137 int8_t byte = value & 0x7F; | |
138 bool byte_sign = byte & 0x40; | |
139 value >>= 7; | |
140 | |
141 if ((value == 0 && !byte_sign) || (value == -1 && byte_sign)) { | |
142 more = false; | |
143 } else { | |
144 byte |= 0x80; | |
145 } | |
146 | |
147 Write<int8_t>(byte); | |
148 } | |
149 } | |
150 | |
151 void WriteString(const char* str) { | |
152 do { | |
153 Write<char>(*str); | |
154 } while (*str++); | |
155 } | |
156 | |
157 private: | |
158 template<typename T> friend class Slot; | |
159 | |
160 template<typename T> | |
161 T* RawSlotAt(uintptr_t offset) { | |
162 ASSERT(offset < capacity_ && offset + sizeof(T) <= capacity_); | |
163 return reinterpret_cast<T*>(&buffer_[offset]); | |
164 } | |
165 | |
166 ELF* elf_; | |
167 uintptr_t position_; | |
168 uintptr_t capacity_; | |
169 byte* buffer_; | |
170 }; | |
171 | |
172 class StringTable; | |
173 | |
174 class ELFSection : public ZoneObject { | |
175 public: | |
176 struct Header { | |
177 uint32_t name; | |
178 uint32_t type; | |
179 uintptr_t flags; | |
180 uintptr_t address; | |
181 uintptr_t offset; | |
182 uintptr_t size; | |
183 uint32_t link; | |
184 uint32_t info; | |
185 uintptr_t alignment; | |
186 uintptr_t entry_size; | |
187 }; | |
188 | |
189 enum Type { | |
190 TYPE_NULL = 0, | |
191 TYPE_PROGBITS = 1, | |
192 TYPE_SYMTAB = 2, | |
193 TYPE_STRTAB = 3, | |
194 TYPE_RELA = 4, | |
195 TYPE_HASH = 5, | |
196 TYPE_DYNAMIC = 6, | |
197 TYPE_NOTE = 7, | |
198 TYPE_NOBITS = 8, | |
199 TYPE_REL = 9, | |
200 TYPE_SHLIB = 10, | |
201 TYPE_DYNSYM = 11, | |
202 TYPE_LOPROC = 0x70000000, | |
203 TYPE_HIPROC = 0x7fffffff, | |
204 TYPE_LOUSER = 0x80000000, | |
205 TYPE_HIUSER = 0xffffffff | |
206 }; | |
207 | |
208 enum Flags { | |
209 FLAG_WRITE = 1, | |
210 FLAG_ALLOC = 2, | |
211 FLAG_EXEC = 4 | |
212 }; | |
213 | |
214 enum SpecialIndexes { | |
215 INDEX_ABSOLUTE = 0xfff1 | |
216 }; | |
217 | |
218 ELFSection(const char* name, Type type, uintptr_t align) | |
219 : name_(name), type_(type), align_(align) { } | |
220 | |
221 virtual ~ELFSection() { } | |
222 | |
223 void PopulateHeader(Writer::Slot<Header> header, StringTable* strtab); | |
224 | |
225 virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { | |
226 uintptr_t start = w->position(); | |
227 if (WriteBody(w)) { | |
228 uintptr_t end = w->position(); | |
229 header->offset = start; | |
230 header->size = end - start; | |
231 } | |
232 } | |
233 | |
234 virtual bool WriteBody(Writer* w) { | |
235 return false; | |
236 } | |
237 | |
238 uint16_t index() const { return index_; } | |
239 void set_index(uint16_t index) { index_ = index; } | |
240 | |
241 protected: | |
242 virtual void PopulateHeader(Writer::Slot<Header> header) { | |
243 header->flags = 0; | |
244 header->address = 0; | |
245 header->offset = 0; | |
246 header->size = 0; | |
247 header->link = 0; | |
248 header->info = 0; | |
249 header->entry_size = 0; | |
250 } | |
251 | |
252 | |
253 private: | |
254 const char* name_; | |
255 Type type_; | |
256 uintptr_t align_; | |
257 uint16_t index_; | |
258 }; | |
259 | |
260 | |
261 class FullHeaderELFSection : public ELFSection { | |
262 public: | |
263 FullHeaderELFSection(const char* name, | |
264 Type type, | |
265 uintptr_t align, | |
266 uintptr_t addr, | |
267 uintptr_t offset, | |
268 uintptr_t size, | |
269 uintptr_t flags) | |
270 : ELFSection(name, type, align), | |
271 addr_(addr), | |
272 offset_(offset), | |
273 size_(size), | |
274 flags_(flags) { } | |
275 | |
276 protected: | |
277 virtual void PopulateHeader(Writer::Slot<Header> header) { | |
278 ELFSection::PopulateHeader(header); | |
279 header->address = addr_; | |
280 header->offset = offset_; | |
281 header->size = size_; | |
282 header->flags = flags_; | |
283 } | |
284 | |
285 private: | |
286 uintptr_t addr_; | |
287 uintptr_t offset_; | |
288 uintptr_t size_; | |
289 uintptr_t flags_; | |
290 }; | |
291 | |
292 | |
293 class StringTable : public ELFSection { | |
294 public: | |
295 explicit StringTable(const char* name) | |
296 : ELFSection(name, TYPE_STRTAB, 1), writer_(NULL), offset_(0), size_(0) { | |
297 } | |
298 | |
299 uintptr_t Add(const char* str) { | |
300 if (*str == '\0') return 0; | |
301 | |
302 uintptr_t offset = size_; | |
303 WriteString(str); | |
304 return offset; | |
305 } | |
306 | |
307 void AttachWriter(Writer* w) { | |
308 writer_ = w; | |
309 offset_ = writer_->position(); | |
310 | |
311 WriteString(""); | |
Erik Corry
2011/01/04 14:21:48
I'm sure there is a good reason why we do this whi
Vyacheslav Egorov (Chromium)
2011/01/18 16:10:42
Done.
| |
312 } | |
313 | |
314 void DetachWriter() { | |
315 writer_ = NULL; | |
316 } | |
317 | |
318 virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { | |
319 ASSERT(writer_ == NULL); | |
320 header->offset = offset_; | |
321 header->size = size_; | |
322 } | |
323 | |
324 private: | |
325 void WriteString(const char* str) { | |
326 uintptr_t written = 0; | |
327 do { | |
328 writer_->Write(*str); | |
329 written++; | |
330 } while (*str++); | |
331 size_ += written; | |
332 } | |
333 | |
334 Writer* writer_; | |
335 | |
336 uintptr_t offset_; | |
337 uintptr_t size_; | |
338 }; | |
339 | |
340 | |
341 void ELFSection::PopulateHeader(Writer::Slot<ELFSection::Header> header, | |
342 StringTable* strtab) { | |
343 header->name = strtab->Add(name_); | |
344 header->type = type_; | |
345 header->alignment = align_; | |
346 PopulateHeader(header); | |
347 } | |
348 | |
349 | |
350 class ELF BASE_EMBEDDED { | |
351 public: | |
352 ELF() : sections_(6) { | |
353 sections_.Add(new ELFSection("", ELFSection::TYPE_NULL, 0)); | |
354 sections_.Add(new StringTable(".shstrtab")); | |
355 } | |
356 | |
357 void Write(Writer* w) { | |
358 WriteHeader(w); | |
359 WriteSectionTable(w); | |
360 WriteSections(w); | |
361 } | |
362 | |
363 ELFSection* SectionAt(uint32_t index) { | |
364 return sections_[index]; | |
365 } | |
366 | |
367 uint32_t AddSection(ELFSection* section) { | |
368 sections_.Add(section); | |
369 section->set_index(sections_.length() - 1); | |
370 return sections_.length() - 1; | |
371 } | |
372 | |
373 private: | |
374 struct ELFHeader { | |
375 uint8_t ident[16]; | |
376 uint16_t type; | |
377 uint16_t machine; | |
378 uint32_t version; | |
379 uintptr_t entry; | |
380 uintptr_t pht_offset; | |
381 uintptr_t sht_offset; | |
382 uint32_t flags; | |
383 uint16_t header_size; | |
384 uint16_t pht_entry_size; | |
385 uint16_t pht_entry_num; | |
386 uint16_t sht_entry_size; | |
387 uint16_t sht_entry_num; | |
388 uint16_t sht_strtab_index; | |
389 }; | |
390 | |
391 | |
392 void WriteHeader(Writer* w) { | |
393 ASSERT(w->position() == 0); | |
394 Writer::Slot<ELFHeader> header = w->SlotHere<ELFHeader>(); | |
395 #if defined(V8_TARGET_ARCH_IA32) | |
396 const uint8_t ident[16] = | |
397 { 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
398 #elif defined(V8_TARGET_ARCH_X64) | |
399 const uint8_t ident[16] = | |
400 { 0x7f, 'E', 'L', 'F', 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
401 #endif | |
Erik Corry
2011/01/04 14:21:48
At least one place in this file should have an els
Vyacheslav Egorov (Chromium)
2011/01/18 16:10:42
Done.
| |
402 memcpy(header->ident, ident, 16); | |
403 header->type = 1; | |
404 #if defined(V8_TARGET_ARCH_IA32) | |
405 header->machine = 3; | |
406 #elif defined(V8_TARGET_ARCH_X64) | |
407 // Processor identification value for x64 is 62 as defined in | |
408 // System V ABI, AMD64 Supplement | |
409 // http://www.x86-64.org/documentation/abi.pdf | |
410 header->machine = 62; | |
411 #endif | |
412 header->version = 1; | |
413 header->entry = 0; | |
414 header->pht_offset = 0; | |
415 header->sht_offset = sizeof(ELFHeader); // Section table follows header. | |
416 header->flags = 0; | |
417 header->header_size = sizeof(ELFHeader); | |
418 header->pht_entry_size = 0; | |
419 header->pht_entry_num = 0; | |
420 header->sht_entry_size = sizeof(ELFSection::Header); | |
421 header->sht_entry_num = sections_.length(); | |
422 header->sht_strtab_index = 1; | |
423 } | |
424 | |
425 void WriteSectionTable(Writer* w) { | |
426 // Section headers table immediately follows file header. | |
427 ASSERT(w->position() == sizeof(ELFHeader)); | |
428 | |
429 Writer::Slot<ELFSection::Header> headers = | |
430 w->SlotsHere<ELFSection::Header>(sections_.length()); | |
431 | |
432 // String table for section table is the first section. | |
433 StringTable* strtab = static_cast<StringTable*>(SectionAt(1)); | |
434 strtab->AttachWriter(w); | |
435 for (int i = 0, length = sections_.length(); | |
436 i < length; | |
437 i++) { | |
438 sections_[i]->PopulateHeader(headers.at(i), strtab); | |
439 } | |
440 strtab->DetachWriter(); | |
441 } | |
442 | |
443 int SectionHeaderPosition(uint32_t section_index) { | |
444 return sizeof(ELFHeader) + sizeof(ELFSection::Header) * section_index; | |
445 } | |
446 | |
447 void WriteSections(Writer* w) { | |
448 Writer::Slot<ELFSection::Header> headers = | |
449 w->SlotAt<ELFSection::Header>(sizeof(ELFHeader)); | |
450 | |
451 for (int i = 0, length = sections_.length(); | |
452 i < length; | |
453 i++) { | |
454 sections_[i]->WriteBody(headers.at(i), w); | |
455 } | |
456 } | |
457 | |
458 ZoneList<ELFSection*> sections_; | |
459 }; | |
460 | |
461 | |
462 class ELFSymbol BASE_EMBEDDED { | |
463 public: | |
464 enum Type { | |
465 TYPE_NOTYPE = 0, | |
466 TYPE_OBJECT = 1, | |
467 TYPE_FUNC = 2, | |
468 TYPE_SECTION = 3, | |
469 TYPE_FILE = 4, | |
470 TYPE_LOPROC = 13, | |
471 TYPE_HIPROC = 15 | |
472 }; | |
473 | |
474 enum Binding { | |
475 BIND_LOCAL = 0, | |
476 BIND_GLOBAL = 1, | |
477 BIND_WEAK = 2, | |
478 BIND_LOPROC = 13, | |
479 BIND_HIPROC = 15 | |
480 }; | |
481 | |
482 ELFSymbol(const char* name, | |
483 uintptr_t value, | |
484 uintptr_t size, | |
485 Binding binding, | |
486 Type type, | |
487 uint16_t section) | |
488 : name(name), | |
489 value(value), | |
490 size(size), | |
491 info((binding << 4) | type), | |
492 other(0), | |
493 section(section) { | |
494 } | |
495 | |
496 Binding binding() const { | |
497 return static_cast<Binding>(info >> 4); | |
498 } | |
499 | |
500 #if defined(V8_TARGET_ARCH_IA32) | |
501 struct SerializedLayout { | |
502 SerializedLayout(uint32_t name, | |
503 uintptr_t value, | |
504 uintptr_t size, | |
505 Binding binding, | |
506 Type type, | |
507 uint16_t section) | |
508 : name(name), | |
509 value(value), | |
510 size(size), | |
511 info((binding << 4) | type), | |
512 other(0), | |
513 section(section) { | |
514 } | |
515 | |
516 uint32_t name; | |
517 uintptr_t value; | |
518 uintptr_t size; | |
519 uint8_t info; | |
520 uint8_t other; | |
521 uint16_t section; | |
522 }; | |
523 #elif defined(V8_TARGET_ARCH_X64) | |
524 struct SerializedLayout { | |
525 SerializedLayout(uint32_t name, | |
526 uintptr_t value, | |
527 uintptr_t size, | |
528 Binding binding, | |
529 Type type, | |
530 uint16_t section) | |
531 : name(name), | |
532 info((binding << 4) | type), | |
533 other(0), | |
534 section(section), | |
535 value(value), | |
536 size(size) { | |
537 } | |
538 | |
539 uint32_t name; | |
540 uint8_t info; | |
541 uint8_t other; | |
542 uint16_t section; | |
543 uintptr_t value; | |
544 uintptr_t size; | |
545 }; | |
546 #endif | |
547 | |
548 void Write(Writer::Slot<SerializedLayout> s, StringTable* t) { | |
549 // Convert symbol names from strings to indexes in the string table. | |
550 s->name = t->Add(name); | |
551 s->value = value; | |
552 s->size = size; | |
553 s->info = info; | |
554 s->other = other; | |
555 s->section = section; | |
556 } | |
557 | |
558 private: | |
559 const char* name; | |
560 uintptr_t value; | |
561 uintptr_t size; | |
562 uint8_t info; | |
563 uint8_t other; | |
564 uint16_t section; | |
565 }; | |
566 | |
567 | |
568 class ELFSymbolTable : public ELFSection { | |
569 public: | |
570 explicit ELFSymbolTable(const char* name) | |
571 : ELFSection(name, TYPE_SYMTAB, sizeof(uintptr_t)), | |
572 locals_(1), | |
573 globals_(1) { | |
574 } | |
575 | |
576 virtual void WriteBody(Writer::Slot<Header> header, Writer* w) { | |
577 w->Align(header->alignment); | |
578 int total_symbols = locals_.length() + globals_.length() + 1; | |
579 header->offset = w->position(); | |
580 | |
581 Writer::Slot<ELFSymbol::SerializedLayout> symbols = | |
582 w->SlotsHere<ELFSymbol::SerializedLayout>(total_symbols); | |
583 | |
584 header->size = w->position() - header->offset; | |
585 | |
586 // String table for this symbol table should follow it in the section table. | |
587 StringTable* strtab = | |
588 static_cast<StringTable*>(w->elf()->SectionAt(index() + 1)); | |
589 strtab->AttachWriter(w); | |
590 symbols.at(0).set(ELFSymbol::SerializedLayout(0, | |
591 0, | |
592 0, | |
593 ELFSymbol::BIND_LOCAL, | |
594 ELFSymbol::TYPE_NOTYPE, | |
595 0)); | |
596 WriteSymbolsList(&locals_, symbols.at(1), strtab); | |
597 WriteSymbolsList(&globals_, symbols.at(locals_.length() + 1), strtab); | |
598 strtab->DetachWriter(); | |
599 } | |
600 | |
601 void Add(const ELFSymbol& symbol) { | |
602 if (symbol.binding() == ELFSymbol::BIND_LOCAL) { | |
603 locals_.Add(symbol); | |
604 } else { | |
605 globals_.Add(symbol); | |
606 } | |
607 } | |
608 | |
609 protected: | |
610 virtual void PopulateHeader(Writer::Slot<Header> header) { | |
611 ELFSection::PopulateHeader(header); | |
612 // We are assuming that string table will follow symbol table. | |
613 header->link = index() + 1; | |
614 header->info = locals_.length() + 1; | |
615 header->entry_size = sizeof(ELFSymbol::SerializedLayout); | |
616 } | |
617 | |
618 private: | |
619 void WriteSymbolsList(const ZoneList<ELFSymbol>* src, | |
620 Writer::Slot<ELFSymbol::SerializedLayout> dst, | |
621 StringTable* strtab) { | |
622 for (int i = 0, len = src->length(); | |
623 i < len; | |
624 i++) { | |
625 src->at(i).Write(dst.at(i), strtab); | |
626 } | |
627 } | |
628 | |
629 ZoneList<ELFSymbol> locals_; | |
630 ZoneList<ELFSymbol> globals_; | |
631 }; | |
632 | |
633 | |
634 class CodeDescription BASE_EMBEDDED { | |
635 public: | |
636 CodeDescription(const char* name, | |
637 Code* code, | |
638 Handle<Script> script, | |
639 GDBJITLineInfo* lineinfo) | |
640 : name_(name), code_(code), script_(script), lineinfo_(lineinfo) | |
641 { } | |
642 | |
643 const char* code_name() const { | |
644 return name_; | |
645 } | |
646 | |
647 uintptr_t code_size() const { | |
648 return code_->instruction_end() - code_->instruction_start(); | |
649 } | |
650 | |
651 uintptr_t code_start() const { | |
652 return (uintptr_t)code_->instruction_start(); | |
653 } | |
654 | |
655 bool is_line_info_available() { | |
656 return !script_.is_null() && | |
657 script_->source()->IsString() && | |
658 script_->HasValidSource() && | |
659 script_->name()->IsString() && | |
660 lineinfo_ != NULL; | |
661 } | |
662 | |
663 GDBJITLineInfo* lineinfo() const { return lineinfo_; } | |
664 | |
665 SmartPointer<char> filename() { | |
666 return String::cast(script_->name())->ToCString(); | |
667 } | |
668 | |
669 int GetScriptLineNumber(int pos) { | |
670 return GetScriptLineNumberSafe(script_, pos) + 1; | |
671 } | |
672 | |
673 private: | |
674 const char* name_; | |
675 Code* code_; | |
676 Handle<Script> script_; | |
677 GDBJITLineInfo* lineinfo_; | |
678 }; | |
679 | |
680 | |
681 static void CreateSymbolsTable(CodeDescription* desc, | |
682 ELF* elf, | |
683 int text_section_index) { | |
684 ELFSymbolTable* symtab = new ELFSymbolTable(".symtab"); | |
685 StringTable* strtab = new StringTable(".strtab"); | |
686 | |
687 // Symbol table should be followed by the linked string table. | |
688 elf->AddSection(symtab); | |
689 elf->AddSection(strtab); | |
690 | |
691 symtab->Add(ELFSymbol("V8 Code", | |
692 0, | |
693 0, | |
694 ELFSymbol::BIND_LOCAL, | |
695 ELFSymbol::TYPE_FILE, | |
696 ELFSection::INDEX_ABSOLUTE)); | |
697 | |
698 symtab->Add(ELFSymbol(desc->code_name(), | |
699 0, | |
700 desc->code_size(), | |
701 ELFSymbol::BIND_GLOBAL, | |
702 ELFSymbol::TYPE_FUNC, | |
703 text_section_index)); | |
704 } | |
705 | |
706 | |
707 class DebugInfoSection : public ELFSection { | |
708 public: | |
709 explicit DebugInfoSection(CodeDescription* desc) | |
710 : ELFSection(".debug_info", TYPE_PROGBITS, 1), desc_(desc) { } | |
711 | |
712 bool WriteBody(Writer* w) { | |
713 Writer::Slot<uint32_t> size = w->SlotHere<uint32_t>(); | |
714 uintptr_t start = w->position(); | |
715 w->Write<uint16_t>(2); // DWARF version. | |
716 w->Write<uint32_t>(0); // Abbreviation table offset. | |
717 w->Write<uint8_t>(sizeof(intptr_t)); | |
718 | |
719 w->WriteULEB128(1); // Abbreviation code. | |
720 w->WriteString(*desc_->filename()); | |
721 w->Write<intptr_t>(desc_->code_start()); | |
722 w->Write<intptr_t>(desc_->code_start() + desc_->code_size()); | |
723 w->Write<uint32_t>(0); | |
724 size.set(static_cast<uint32_t>(w->position() - start)); | |
725 return true; | |
726 } | |
727 | |
728 private: | |
729 CodeDescription* desc_; | |
730 }; | |
731 | |
732 | |
733 class DebugAbbrevSection : public ELFSection { | |
734 public: | |
735 DebugAbbrevSection() : ELFSection(".debug_abbrev", TYPE_PROGBITS, 1) { } | |
736 | |
737 // DWARF2 standard, figure 14. | |
738 enum DWARF2Tags { | |
739 DW_TAG_COMPILE_UNIT = 0x11 | |
740 }; | |
741 | |
742 // DWARF2 standard, figure 16. | |
743 enum DWARF2ChildrenDetermination { | |
744 DW_CHILDREN_NO = 0, | |
745 DW_CHILDREN_YES = 1 | |
746 }; | |
747 | |
748 // DWARF standard, figure 17. | |
749 enum DWARF2Attribute { | |
750 DW_AT_NAME = 0x3, | |
751 DW_AT_STMT_LIST = 0x10, | |
752 DW_AT_LOW_PC = 0x11, | |
753 DW_AT_HIGH_PC = 0x12 | |
754 }; | |
755 | |
756 // DWARF2 standard, figure 19. | |
757 enum DWARF2AttributeForm { | |
758 DW_FORM_ADDR = 0x1, | |
759 DW_FORM_STRING = 0x8, | |
760 DW_FORM_DATA4 = 0x6 | |
761 }; | |
762 | |
763 bool WriteBody(Writer* w) { | |
764 w->WriteULEB128(1); | |
765 w->WriteULEB128(DW_TAG_COMPILE_UNIT); | |
766 w->Write<uint8_t>(DW_CHILDREN_NO); | |
767 w->WriteULEB128(DW_AT_NAME); | |
768 w->WriteULEB128(DW_FORM_STRING); | |
769 w->WriteULEB128(DW_AT_LOW_PC); | |
770 w->WriteULEB128(DW_FORM_ADDR); | |
771 w->WriteULEB128(DW_AT_HIGH_PC); | |
772 w->WriteULEB128(DW_FORM_ADDR); | |
773 w->WriteULEB128(DW_AT_STMT_LIST); | |
774 w->WriteULEB128(DW_FORM_DATA4); | |
775 w->WriteULEB128(0); | |
776 w->WriteULEB128(0); | |
777 w->WriteULEB128(0); | |
778 return true; | |
779 } | |
780 }; | |
781 | |
782 | |
783 class DebugLineSection : public ELFSection { | |
784 public: | |
785 explicit DebugLineSection(CodeDescription* desc) | |
786 : ELFSection(".debug_line", TYPE_PROGBITS, 1), | |
787 desc_(desc) { } | |
788 | |
789 // DWARF2 standard, figure 34. | |
790 enum DWARF2Opcodes { | |
791 DW_LNS_COPY = 1, | |
792 DW_LNS_ADVANCE_PC = 2, | |
793 DW_LNS_ADVANCE_LINE = 3, | |
794 DW_LNS_SET_FILE = 4, | |
795 DW_LNS_SET_COLUMN = 5, | |
796 DW_LNS_NEGATE_STMT = 6 | |
797 }; | |
798 | |
799 // DWARF2 standard, figure 35. | |
800 enum DWARF2ExtendedOpcode { | |
801 DW_LNE_END_SEQUENCE = 1, | |
802 DW_LNE_SET_ADDRESS = 2, | |
803 DW_LNE_DEFINE_FILE = 3 | |
804 }; | |
805 | |
806 bool WriteBody(Writer* w) { | |
807 // Write prologue. | |
808 Writer::Slot<uint32_t> total_length = w->SlotHere<uint32_t>(); | |
809 uintptr_t start = w->position(); | |
810 | |
811 w->Write<uint16_t>(2); // Field version. | |
812 Writer::Slot<uint32_t> prologue_length = w->SlotHere<uint32_t>(); | |
813 uintptr_t prologue_start = w->position(); | |
814 w->Write<uint8_t>(1); // Field minimum_instruction_length. | |
815 w->Write<uint8_t>(1); // Field default_is_stmt. | |
816 w->Write<int8_t>(0); // Field line_base. | |
817 w->Write<uint8_t>(2); // Field line_range. | |
818 w->Write<uint8_t>(DW_LNS_NEGATE_STMT + 1); // Field opcode_base. | |
819 w->Write<uint8_t>(0); // DW_LNS_COPY operands count. | |
820 w->Write<uint8_t>(1); // DW_LNS_ADVANCE_PC operands count. | |
821 w->Write<uint8_t>(1); // DW_LNS_ADVANCE_LINE operands count. | |
822 w->Write<uint8_t>(1); // DW_LNS_SET_FILE operands count. | |
823 w->Write<uint8_t>(1); // DW_LNS_SET_COLUMN operands count. | |
824 w->Write<uint8_t>(0); // DW_LNS_NEGATE_STMT operands count. | |
825 w->Write<uint8_t>(0); // Empty include_directories sequence. | |
826 w->WriteString(*desc_->filename()); // File name. | |
827 w->WriteULEB128(0); // Current directory. | |
828 w->WriteULEB128(0); // Unknown modification time. | |
829 w->WriteULEB128(0); // Unknown file size. | |
830 w->Write<uint8_t>(0); | |
831 prologue_length.set(static_cast<uint32_t>(w->position() - prologue_start)); | |
832 | |
833 WriteExtendedOpcode(w, DW_LNE_SET_ADDRESS, sizeof(intptr_t)); | |
834 w->Write<intptr_t>(desc_->code_start()); | |
835 | |
836 intptr_t pc = 0; | |
837 intptr_t line = 1; | |
838 bool is_statement = true; | |
839 | |
840 List<GDBJITLineInfo::PCInfo>* pc_info = desc_->lineinfo()->pc_info(); | |
841 for (int i = 0; i < pc_info->length(); i++) { | |
842 GDBJITLineInfo::PCInfo* info = &pc_info->at(i); | |
843 uintptr_t pc_diff = info->pc_ - pc; | |
844 ASSERT(info->pc_ >= pc); | |
845 if (pc_diff != 0) { | |
846 w->Write<uint8_t>(DW_LNS_ADVANCE_PC); | |
847 w->WriteSLEB128(pc_diff); | |
848 pc += pc_diff; | |
849 } | |
850 intptr_t line_diff = desc_->GetScriptLineNumber(info->pos_) - line; | |
851 if (line_diff != 0) { | |
852 w->Write<uint8_t>(DW_LNS_ADVANCE_LINE); | |
853 w->WriteSLEB128(line_diff); | |
854 line += line_diff; | |
855 } | |
856 if (is_statement != info->is_statement_) { | |
857 w->Write<uint8_t>(DW_LNS_NEGATE_STMT); | |
858 is_statement = !is_statement; | |
Erik Corry
2011/01/04 14:21:48
How about is_statement = info->is_statement_;
Vyacheslav Egorov (Chromium)
2011/01/18 16:10:42
I want to reflect the meaning of an emitted operat
| |
859 } | |
860 if (pc_diff != 0 || i == 0) { | |
861 w->Write<uint8_t>(DW_LNS_COPY); | |
862 } | |
863 } | |
864 WriteExtendedOpcode(w, DW_LNE_END_SEQUENCE, 0); | |
865 total_length.set(static_cast<uint32_t>(w->position() - start)); | |
866 return true; | |
867 } | |
868 | |
869 private: | |
870 void WriteExtendedOpcode(Writer* w, | |
871 DWARF2ExtendedOpcode op, | |
872 size_t operands_size) { | |
873 w->Write<uint8_t>(0); | |
874 w->WriteULEB128(operands_size + 1); | |
875 w->Write<uint8_t>(op); | |
876 } | |
877 | |
878 CodeDescription* desc_; | |
879 }; | |
880 | |
881 | |
882 static void CreateDWARFSections(CodeDescription* desc, ELF* elf) { | |
883 if (desc->is_line_info_available()) { | |
884 elf->AddSection(new DebugInfoSection(desc)); | |
885 elf->AddSection(new DebugAbbrevSection); | |
886 elf->AddSection(new DebugLineSection(desc)); | |
887 } | |
888 } | |
889 | |
890 | |
891 // ------------------------------------------------------------------- | |
892 // GDB JIT Interface declarations copied as is from | |
893 // http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html | |
894 extern "C" { | |
895 typedef enum { | |
896 JIT_NOACTION = 0, | |
897 JIT_REGISTER_FN, | |
898 JIT_UNREGISTER_FN | |
899 } jit_actions_t; | |
900 | |
901 struct jit_code_entry { | |
902 struct jit_code_entry *next_entry; | |
903 struct jit_code_entry *prev_entry; | |
904 char *symfile_addr; | |
905 uint64_t symfile_size; | |
906 }; | |
907 | |
908 struct jit_descriptor { | |
909 uint32_t version; | |
910 uint32_t action_flag; | |
911 struct jit_code_entry *relevant_entry; | |
912 struct jit_code_entry *first_entry; | |
913 }; | |
914 | |
915 void __attribute__((noinline)) __jit_debug_register_code() { | |
916 __asm__ (""); | |
917 } | |
918 | |
919 struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; | |
920 } | |
921 | |
922 | |
923 static jit_code_entry* CreateCodeEntry(byte* symfile_addr, | |
924 uintptr_t symfile_size) { | |
925 jit_code_entry* entry = static_cast<jit_code_entry*>( | |
926 malloc(sizeof(jit_code_entry) + symfile_size)); | |
927 | |
928 entry->symfile_addr = reinterpret_cast<char*>(entry + 1); | |
929 entry->symfile_size = symfile_size; | |
930 memcpy(entry->symfile_addr, symfile_addr, symfile_size); | |
931 | |
932 entry->prev_entry = entry->next_entry = NULL; | |
933 | |
934 return entry; | |
935 } | |
936 | |
937 | |
938 static void DestroyCodeEntry(jit_code_entry* entry) { | |
939 free(entry); | |
940 } | |
941 | |
942 | |
943 static void RegisterCodeEntry(jit_code_entry* entry) { | |
944 entry->next_entry = __jit_debug_descriptor.first_entry; | |
945 if (entry->next_entry != NULL) entry->next_entry->prev_entry = entry; | |
946 __jit_debug_descriptor.first_entry = | |
947 __jit_debug_descriptor.relevant_entry = entry; | |
948 | |
949 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; | |
950 __jit_debug_register_code(); | |
951 } | |
952 | |
953 | |
954 static void UnregisterCodeEntry(jit_code_entry* entry) { | |
955 if (entry->prev_entry != NULL) { | |
956 entry->prev_entry->next_entry = entry->next_entry; | |
957 } else { | |
958 __jit_debug_descriptor.first_entry = entry->next_entry; | |
959 } | |
960 | |
961 if (entry->next_entry != NULL) { | |
962 entry->next_entry->prev_entry = entry->prev_entry; | |
963 } | |
964 | |
965 __jit_debug_descriptor.relevant_entry = entry; | |
966 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; | |
967 __jit_debug_register_code(); | |
968 } | |
969 | |
970 | |
971 static jit_code_entry* CreateELFObject(CodeDescription* desc) { | |
972 ZoneScope zone_scope(DELETE_ON_EXIT); | |
973 | |
974 ELF elf; | |
975 Writer w(&elf); | |
976 | |
977 int text_section_index = elf.AddSection( | |
978 new FullHeaderELFSection(".text", | |
979 ELFSection::TYPE_NOBITS, | |
980 kCodeAlignment, | |
981 desc->code_start(), | |
982 0, | |
983 desc->code_size(), | |
984 ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC)); | |
985 | |
986 CreateSymbolsTable(desc, &elf, text_section_index); | |
987 | |
988 CreateDWARFSections(desc, &elf); | |
989 | |
990 elf.Write(&w); | |
991 | |
992 return CreateCodeEntry(w.buffer(), w.position()); | |
993 } | |
994 | |
995 | |
996 static bool SameCodeObjects(void* key1, void* key2) { | |
997 return key1 == key2; | |
998 } | |
999 | |
1000 | |
1001 static HashMap entries(&SameCodeObjects); | |
1002 | |
1003 | |
1004 static uint32_t HashForCodeObject(Code* code) { | |
1005 static const uintptr_t kGoldenRatio = 2654435761u; | |
1006 uintptr_t hash = reinterpret_cast<uintptr_t>(code->address()); | |
1007 return static_cast<uint32_t>((hash >> kCodeAlignmentBits) * kGoldenRatio); | |
1008 } | |
1009 | |
1010 | |
1011 static const intptr_t kLineInfoTag = 0x1; | |
1012 | |
1013 | |
1014 static bool IsLineInfoTagged(void* ptr) { | |
1015 return 0 != (reinterpret_cast<intptr_t>(ptr) & kLineInfoTag); | |
1016 } | |
1017 | |
1018 | |
1019 static void* TagLineInfo(GDBJITLineInfo* ptr) { | |
1020 return reinterpret_cast<void*>( | |
1021 reinterpret_cast<intptr_t>(ptr) | kLineInfoTag); | |
1022 } | |
1023 | |
1024 | |
1025 static GDBJITLineInfo* UntagLineInfo(void* ptr) { | |
1026 return reinterpret_cast<GDBJITLineInfo*>( | |
1027 reinterpret_cast<intptr_t>(ptr) & ~kLineInfoTag); | |
1028 } | |
1029 | |
1030 | |
1031 void GDBJITInterface::AddCode(Handle<String> name, | |
1032 Handle<Script> script, | |
1033 Handle<Code> code) { | |
1034 if (!FLAG_gdbjit) return; | |
1035 | |
1036 // Force initialization of line_ends array. | |
1037 GetScriptLineNumber(script, 0); | |
1038 | |
1039 if (!name.is_null()) { | |
1040 SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); | |
1041 AddCode(*name_cstring, *code, *script); | |
1042 } else { | |
1043 AddCode("", *code, *script); | |
1044 } | |
1045 } | |
1046 | |
1047 | |
1048 void GDBJITInterface::AddCode(const char* name, | |
1049 Code* code, | |
1050 Script* script) { | |
1051 if (!FLAG_gdbjit) return; | |
1052 AssertNoAllocation no_gc; | |
1053 | |
1054 HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); | |
1055 if (e->value != NULL && !IsLineInfoTagged(e->value)) return; | |
1056 | |
1057 GDBJITLineInfo* lineinfo = UntagLineInfo(e->value); | |
1058 CodeDescription code_desc(name, | |
1059 code, | |
1060 script != NULL ? Handle<Script>(script) | |
1061 : Handle<Script>(), | |
1062 lineinfo); | |
1063 | |
1064 if (!FLAG_gdbjit_full && !code_desc.is_line_info_available()) { | |
1065 delete lineinfo; | |
1066 entries.Remove(code, HashForCodeObject(code)); | |
1067 return; | |
1068 } | |
1069 | |
1070 jit_code_entry* entry = CreateELFObject(&code_desc); | |
1071 ASSERT(!IsLineInfoTagged(entry)); | |
1072 | |
1073 delete lineinfo; | |
1074 e->value = entry; | |
1075 | |
1076 RegisterCodeEntry(entry); | |
1077 } | |
1078 | |
1079 | |
1080 void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, | |
1081 const char* name, | |
1082 Code* code) { | |
1083 if (!FLAG_gdbjit) return; | |
1084 | |
1085 EmbeddedVector<char, 256> buffer; | |
1086 StringBuilder builder(buffer.start(), buffer.length()); | |
1087 | |
1088 builder.AddString(Tag2String(tag)); | |
1089 if ((name != NULL) && (*name != '\0')) { | |
1090 builder.AddString(": "); | |
1091 builder.AddString(name); | |
1092 } else { | |
1093 builder.AddFormatted(": code object %p", static_cast<void*>(code)); | |
1094 } | |
1095 | |
1096 AddCode(builder.Finalize(), code); | |
1097 } | |
1098 | |
1099 | |
1100 void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, | |
1101 String* name, | |
1102 Code* code) { | |
1103 if (!FLAG_gdbjit) return; | |
1104 AddCode(tag, name != NULL ? *name->ToCString(DISALLOW_NULLS) : NULL, code); | |
1105 } | |
1106 | |
1107 | |
1108 void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, Code* code) { | |
1109 if (!FLAG_gdbjit) return; | |
1110 | |
1111 AddCode(tag, "", code); | |
1112 } | |
1113 | |
1114 | |
1115 void GDBJITInterface::RemoveCode(Code* code) { | |
1116 if (!FLAG_gdbjit) return; | |
1117 | |
1118 HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), false); | |
1119 if (e == NULL) return; | |
1120 | |
1121 if (IsLineInfoTagged(e->value)) { | |
1122 delete UntagLineInfo(e->value); | |
1123 } else { | |
1124 jit_code_entry* entry = static_cast<jit_code_entry*>(e->value); | |
1125 UnregisterCodeEntry(entry); | |
1126 DestroyCodeEntry(entry); | |
1127 } | |
1128 e->value = NULL; | |
1129 entries.Remove(code, HashForCodeObject(code)); | |
1130 } | |
1131 | |
1132 | |
1133 void GDBJITInterface::RegisterDetailedLineInfo(Code* code, | |
1134 GDBJITLineInfo* line_info) { | |
1135 ASSERT(!IsLineInfoTagged(line_info)); | |
1136 HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); | |
1137 ASSERT(e->value == NULL); | |
1138 e->value = TagLineInfo(line_info); | |
1139 } | |
1140 | |
1141 | |
1142 } } // namespace v8::internal | |
1143 #endif | |
OLD | NEW |