tools/elf4rom/src/dwarflinemanager.cpp
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/elf4rom/src/dwarflinemanager.cpp	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,185 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU Lesser General Public License for more details.
+* 
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+#include "dwarfmanager.h"
+#include "inputfile.h"
+
+const string DwarfLineManager::iLineSectionName(".debug_line");
+
+inline static size_t process_extended_line_op (FileShdrPair & aPair, Dwarf_Byte_Ptr data)
+{
+	size_t bytes_read;
+	size_t len = (size_t)ULEB128(data, bytes_read);
+
+	if (len == 0){
+		cerr << "badly formed extended line op encountered!\n";
+		// a length of 0 indicates a badly formed op and will force everything to be ignored until 'end_of_sequence'.
+		return 0;
+	}
+
+	len += bytes_read;
+	unsigned char op_code = *data++;
+  	switch (op_code){
+    case DW_LNE_end_sequence:
+      	break;
+    case DW_LNE_set_address: {
+    	size_t size = len - bytes_read - 1;
+		LinearAddr addr = GetValue(data, size);
+		LinearAddr relocatedAddress = aPair.iXIPFileDetails.Relocate(addr);
+		if (addr != relocatedAddress)
+			WriteValue(data, relocatedAddress, size);
+		break;
+    	}
+    case DW_LNE_define_file:
+      	ULEB128(data, bytes_read);
+      	ULEB128(data, bytes_read);
+      	ULEB128(data, bytes_read);
+      	break;     
+    default:
+
+    	break;
+    }
+
+  return len;
+}
+
+void DwarfLineManager::ProcessSection(FileShdrPair & aPair, Dwarf_Byte_Ptr aStart, Dwarf_Byte_Ptr aEnd){
+	Dwarf_Byte_Ptr start = aStart;
+	Dwarf_Byte_Ptr end = aEnd;
+	size_t bytes_read = 0;
+	while (start < end){
+		Dwarf_Byte_Ptr hdrptr = start;		
+		size_t offset_size, initial_length_size;
+		
+		Dwarf_Word length = READ_UNALIGNED4(hdrptr); 
+		hdrptr += 4;
+
+		if (length >= 0xfffffff0u) {
+			cerr << "Error: 64 bit DWARF not supported\n";
+			exit(EXIT_FAILURE);
+		} else {	
+			offset_size = 4;
+			initial_length_size = 4;
+		}
+		
+		Dwarf_Byte_Ptr end_of_sequence = start + length + initial_length_size;
+
+		Dwarf_Half version = READ_UNALIGNED2(hdrptr);
+		hdrptr += 2;
+
+		if (version != 2 && version != 3){
+			static bool warned = false;
+			if (!warned){
+				cerr << "Only DWARF 2 and 3 aranges are currently supported\n";
+				warned = true;
+			}
+			return;
+		}
+		
+		hdrptr += offset_size;
+#if 0
+		// Don't need the next four fields 
+		Dwarf_Ubyte min_insn_length = *hdrptr++;   
+		Dwarf_Ubyte default_is_stmt = *hdrptr++;
+		Dwarf_Ubyte line_base = *hdrptr++;
+		Dwarf_Ubyte line_range = *hdrptr++;
+#endif
+		hdrptr +=4;
+		Dwarf_Ubyte opcode_base = *hdrptr++;
+
+	    /* Skip the contents of the Opcodes table.  */
+		Dwarf_Byte_Ptr standard_opcodes = hdrptr;
+		start = standard_opcodes + opcode_base - 1;
+
+		/* skip the contents of the Directory table.  */
+		while (*start != 0){
+			start += strlen ((char *) start) + 1;
+		}
+		/* Skip the NUL at the end of the table.  */
+		start++;
+
+		/* skip the contents of the File Name table.  */
+		while (*start != 0){
+			start += strlen ((char *) start) + 1;
+
+			ULEB128(start, bytes_read);
+			ULEB128(start, bytes_read);
+			ULEB128(start, bytes_read);
+		}
+		/* Skip the NUL at the end of the table.  */
+		start++;
+	   
+		while (start < end_of_sequence){
+			unsigned char op_code = *start++;
+
+			if (op_code >= opcode_base){
+				continue;
+			} else {
+				switch (op_code){
+// missing from dwarf.h - first byte of extended op codes is '0x0'
+#define DW_LNS_extended_op 0x0
+				case DW_LNS_extended_op:
+					size_t n = process_extended_line_op (aPair, start);
+					// if we don't understand the extended op skip to the end of the sequence :-(
+					if (n == 0)
+						start = end_of_sequence;
+					else 
+						start += n;
+					break;
+
+				case DW_LNS_copy:
+					break;
+
+				case DW_LNS_advance_pc:
+				case DW_LNS_advance_line:
+				case DW_LNS_set_file:
+				case DW_LNS_set_column:
+					ULEB128(start, bytes_read);
+					break;
+
+				case DW_LNS_negate_stmt:
+				case DW_LNS_set_basic_block:
+				case DW_LNS_const_add_pc:
+					break;
+
+				case DW_LNS_fixed_advance_pc:
+					start += 2;
+					break;
+
+				case DW_LNS_set_prologue_end:
+				case DW_LNS_set_epilogue_begin:
+					break;
+
+				case DW_LNS_set_isa:
+					ULEB128(start, bytes_read);
+					break;
+
+				default:
+					for (int i = standard_opcodes[op_code - 1]; i > 0 ; --i){
+						ULEB128(start, bytes_read);
+					}
+					break;
+				}
+			}
+		}
+		// !! eek ARM seems to require header word aligned - at least for Dwarf 2
+		if (aPair.iXIPFileDetails.iRVCTProduced && (version == 2))
+			start = (Dwarf_Byte_Ptr)(((unsigned long)start + 3) & ~3);
+	}
+}