Index: src/gdb-jit.cc |
=================================================================== |
--- src/gdb-jit.cc (revision 6798) |
+++ src/gdb-jit.cc (working copy) |
@@ -395,7 +395,7 @@ |
void WriteHeader(Writer* w) { |
ASSERT(w->position() == 0); |
Writer::Slot<ELFHeader> header = w->CreateSlotHere<ELFHeader>(); |
-#if defined(V8_TARGET_ARCH_IA32) |
+#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_ARM) |
const uint8_t ident[16] = |
{ 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
#elif defined(V8_TARGET_ARCH_X64) |
@@ -413,6 +413,10 @@ |
// System V ABI, AMD64 Supplement |
// http://www.x86-64.org/documentation/abi.pdf |
header->machine = 62; |
+#elif defined(V8_TARGET_ARCH_ARM) |
+ // Set to EM_ARM, defined as 40, in "ARM ELF File Format" at |
+ // infocenter.arm.com/help/topic/com.arm.doc.dui0101a/DUI0101A_Elf.pdf |
+ header->machine = 40; |
#else |
#error Unsupported target architecture. |
#endif |
@@ -503,8 +507,7 @@ |
Binding binding() const { |
return static_cast<Binding>(info >> 4); |
} |
- |
-#if defined(V8_TARGET_ARCH_IA32) |
+#if defined(V8_TARGET_ARCH_IA32) || defined(V8_TARGET_ARCH_ARM) |
struct SerializedLayout { |
SerializedLayout(uint32_t name, |
uintptr_t value, |
@@ -857,14 +860,20 @@ |
Writer::Slot<uint32_t> total_length = w->CreateSlotHere<uint32_t>(); |
uintptr_t start = w->position(); |
+ // Used for special opcodes |
+ const int8_t line_base = 1; |
+ const uint8_t line_range = 7; |
+ const int8_t max_line_incr = (line_base + line_range - 1); |
+ const uint8_t opcode_base = DW_LNS_NEGATE_STMT + 1; |
+ |
w->Write<uint16_t>(2); // Field version. |
Writer::Slot<uint32_t> prologue_length = w->CreateSlotHere<uint32_t>(); |
uintptr_t prologue_start = w->position(); |
w->Write<uint8_t>(1); // Field minimum_instruction_length. |
w->Write<uint8_t>(1); // Field default_is_stmt. |
- w->Write<int8_t>(0); // Field line_base. |
- w->Write<uint8_t>(2); // Field line_range. |
- w->Write<uint8_t>(DW_LNS_NEGATE_STMT + 1); // Field opcode_base. |
+ w->Write<int8_t>(line_base); // Field line_base. |
+ w->Write<uint8_t>(line_range); // Field line_range. |
+ w->Write<uint8_t>(opcode_base); // Field opcode_base. |
w->Write<uint8_t>(0); // DW_LNS_COPY operands count. |
w->Write<uint8_t>(1); // DW_LNS_ADVANCE_PC operands count. |
w->Write<uint8_t>(1); // DW_LNS_ADVANCE_LINE operands count. |
@@ -881,6 +890,7 @@ |
WriteExtendedOpcode(w, DW_LNE_SET_ADDRESS, sizeof(intptr_t)); |
w->Write<intptr_t>(desc_->CodeStart()); |
+ w->Write<uint8_t>(DW_LNS_COPY); |
intptr_t pc = 0; |
intptr_t line = 1; |
@@ -888,29 +898,66 @@ |
List<GDBJITLineInfo::PCInfo>* pc_info = desc_->lineinfo()->pc_info(); |
pc_info->Sort(&ComparePCInfo); |
- for (int i = 0; i < pc_info->length(); i++) { |
+ |
+ int pc_info_length = pc_info->length(); |
+ for (int i = 0; i < pc_info_length; i++) { |
GDBJITLineInfo::PCInfo* info = &pc_info->at(i); |
+ ASSERT(info->pc_ >= pc); |
+ |
+ // Reduce bloating in the debug line table by removing duplicate line |
+ // entries (per DWARF2 standard). |
+ intptr_t new_line = desc_->GetScriptLineNumber(info->pos_); |
+ if (new_line == line) { |
+ continue; |
+ } |
+ |
+ // Mark statement boundaries. For a better debugging experience, mark |
+ // the last pc address in the function as a statement (e.g. "}"), so that |
+ // a user can see the result of the last line executed in the function, |
+ // should control reach the end. |
+ if ((i+1) == pc_info_length) { |
+ if (!is_statement) { |
+ w->Write<uint8_t>(DW_LNS_NEGATE_STMT); |
+ } |
+ } else if (is_statement != info->is_statement_) { |
+ w->Write<uint8_t>(DW_LNS_NEGATE_STMT); |
+ is_statement = !is_statement; |
+ } |
+ |
+ // Generate special opcodes, if possible. This results in more compact |
+ // debug line tables. See the DWARF 2.0 standard to learn more about |
+ // special opcodes. |
uintptr_t pc_diff = info->pc_ - pc; |
- ASSERT(info->pc_ >= pc); |
- if (pc_diff != 0) { |
+ intptr_t line_diff = new_line - line; |
+ |
+ // Compute special opcode (see DWARF 2.0 standard) |
+ intptr_t special_opcode = (line_diff - line_base) + |
+ (line_range * pc_diff) + opcode_base; |
+ |
+ // If special_opcode is less than or equal to 255, it can be used as a |
+ // special opcode. If line_diff is larger than the max line increment |
+ // allowed for a special opcode, or if line_diff is less than the minimum |
+ // line that can be added to the line register (i.e. line_base), then |
+ // special_opcode can't be used. |
+ if ((special_opcode >= opcode_base) && (special_opcode <= 255) && |
+ (line_diff <= max_line_incr) && (line_diff >= line_base)) { |
+ w->Write<uint8_t>(special_opcode); |
+ } else { |
w->Write<uint8_t>(DW_LNS_ADVANCE_PC); |
w->WriteSLEB128(pc_diff); |
- pc += pc_diff; |
- } |
- intptr_t line_diff = desc_->GetScriptLineNumber(info->pos_) - line; |
- if (line_diff != 0) { |
w->Write<uint8_t>(DW_LNS_ADVANCE_LINE); |
w->WriteSLEB128(line_diff); |
- line += line_diff; |
- } |
- if (is_statement != info->is_statement_) { |
- w->Write<uint8_t>(DW_LNS_NEGATE_STMT); |
- is_statement = !is_statement; |
- } |
- if (pc_diff != 0 || i == 0) { |
w->Write<uint8_t>(DW_LNS_COPY); |
} |
+ |
+ // Increment the pc and line operands. |
+ pc += pc_diff; |
+ line += line_diff; |
} |
+ // Advance the pc to the end of the routine, since the end sequence opcode |
+ // requires this. |
+ w->Write<uint8_t>(DW_LNS_ADVANCE_PC); |
+ w->WriteSLEB128(desc_->CodeSize() - pc); |
WriteExtendedOpcode(w, DW_LNE_END_SEQUENCE, 0); |
total_length.set(static_cast<uint32_t>(w->position() - start)); |
return true; |
@@ -1237,6 +1284,20 @@ |
static void RegisterCodeEntry(JITCodeEntry* entry) { |
+#if defined(DEBUG) && !defined(WIN32) |
+ static int file_num = 0; |
+ if (FLAG_gdbjit_dump) { |
+ static const int kMaxFileNameSize = 64; |
+ static const char* kElfFilePrefix = "/tmp/elfdump"; |
+ static const char* kObjFileExt = ".o"; |
+ char file_name[64]; |
+ |
+ OS::SNPrintF(Vector<char>(file_name, kMaxFileNameSize), "%s%d%s", |
+ kElfFilePrefix, file_num++, kObjFileExt); |
+ WriteBytes(file_name, entry->symfile_addr_, entry->symfile_size_); |
+ } |
+#endif |
+ |
entry->next_ = __jit_debug_descriptor.first_entry_; |
if (entry->next_ != NULL) entry->next_->prev_ = entry; |
__jit_debug_descriptor.first_entry_ = |
@@ -1294,7 +1355,13 @@ |
} |
-static HashMap entries(&SameCodeObjects); |
+static HashMap* GetEntries() { |
+ static HashMap* entries = NULL; |
+ if (entries == NULL) { |
+ entries = new HashMap(&SameCodeObjects); |
+ } |
+ return entries; |
+} |
static uint32_t HashForCodeObject(Code* code) { |
@@ -1398,7 +1465,7 @@ |
if (!FLAG_gdbjit) return; |
AssertNoAllocation no_gc; |
- HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); |
+ HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true); |
if (e->value != NULL && !IsLineInfoTagged(e->value)) return; |
GDBJITLineInfo* lineinfo = UntagLineInfo(e->value); |
@@ -1411,7 +1478,7 @@ |
if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { |
delete lineinfo; |
- entries.Remove(code, HashForCodeObject(code)); |
+ GetEntries()->Remove(code, HashForCodeObject(code)); |
return; |
} |
@@ -1464,7 +1531,9 @@ |
void GDBJITInterface::RemoveCode(Code* code) { |
if (!FLAG_gdbjit) return; |
- HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), false); |
+ HashMap::Entry* e = GetEntries()->Lookup(code, |
+ HashForCodeObject(code), |
+ false); |
if (e == NULL) return; |
if (IsLineInfoTagged(e->value)) { |
@@ -1475,14 +1544,14 @@ |
DestroyCodeEntry(entry); |
} |
e->value = NULL; |
- entries.Remove(code, HashForCodeObject(code)); |
+ GetEntries()->Remove(code, HashForCodeObject(code)); |
} |
void GDBJITInterface::RegisterDetailedLineInfo(Code* code, |
GDBJITLineInfo* line_info) { |
ASSERT(!IsLineInfoTagged(line_info)); |
- HashMap::Entry* e = entries.Lookup(code, HashForCodeObject(code), true); |
+ HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true); |
ASSERT(e->value == NULL); |
e->value = TagLineInfo(line_info); |
} |