fixed bugs that caused incorrect address lookups:

* source file registry entry was ignored in line entries
* extended opcode length is a leb128
* end_sequence opcode should add new line entry, and then reset registry
* implemented opcode DW_LNS_const_add_pc
* getDebugInfo() incorrectly matched prologue line entries

added main() to generate output comparable with that of msp430-addr2line
(verified with msp430-gcc v4.5.3).
This commit is contained in:
Fredrik Osterlind 2012-04-27 12:45:17 +02:00
parent b0dafb710c
commit d2f2f4cea9
1 changed files with 146 additions and 49 deletions

View File

@ -39,21 +39,22 @@
package se.sics.mspsim.debug;
import java.io.File;
import java.util.ArrayList;
import se.sics.mspsim.util.DebugInfo;
import se.sics.mspsim.util.ELFDebug;
import se.sics.mspsim.util.Utils;
import se.sics.mspsim.util.ELF;
import se.sics.mspsim.util.ELFDebug;
import se.sics.mspsim.util.ELFSection;
import se.sics.mspsim.util.Utils;
public class DwarfReader implements ELFDebug {
public static final boolean DEBUG = false;
/* Operands for lines */
public static final int DW_LNS_EXT = 0;
public static final int DW_LNS_copy = 1;
public static final int DW_LNS_advance_pc = 2;
public static final int DW_LNS_advance_line = 3;
@ -63,13 +64,16 @@ public class DwarfReader implements ELFDebug {
public static final int DW_LNS_set_basic_block = 7;
public static final int DW_LNS_const_add_pc = 8;
public static final int DW_LNS_fixed_advance_pc = 9;
public static final int DW_LNS_set_prologue_end = 10;
public static final int DW_LNS_set_epilogue_begin = 11;
public static final int DW_LNS_set_isa = 12;
/* Extended operands (preceded by DW_LNS_EXT + len) */
public static final int DW_LNE_end_sequence = 1;
public static final int DW_LNE_set_address = 2;
public static final int DW_LNE_set_address = 2;
public static final int DW_LNE_define_file = 3;
public static final int DW_LNE_set_discriminator = 4; /* DWARF > 2.0 */
ELF elfFile;
/* Address ranges */
@ -84,9 +88,11 @@ public class DwarfReader implements ELFDebug {
class LineEntry {
int address;
int line;
LineEntry(int line, int adr) {
int file;
LineEntry(int line, int adr, int file) {
this.line = line;
address = adr;
this.address = adr;
this.file = file;
}
}
/* Line number lookup data */
@ -97,7 +103,7 @@ public class DwarfReader implements ELFDebug {
}
ArrayList<LineData> lineInfo = new ArrayList<LineData>();
/* some state for the line number handling */
private int lineAddress;
private int lineFile;
@ -106,9 +112,9 @@ public class DwarfReader implements ELFDebug {
private boolean isBasicBlock = false;
private boolean isStatement = false;
private boolean endSequence = false;
private ArrayList<Arange> aranges = new ArrayList<Arange>();
public DwarfReader(ELF elfFile) {
this.elfFile = elfFile;
}
@ -130,6 +136,7 @@ public class DwarfReader implements ELFDebug {
if (DEBUG) {
System.out.println("DWARF Line - ELF Section length: " + sec.getSize());
}
sec.reset();
int endPos = 0;
ArrayList<LineEntry> lineData = new ArrayList<LineEntry>();
@ -142,7 +149,7 @@ public class DwarfReader implements ELFDebug {
int minOpLen = sec.readElf8();
int defaultIsStmt = sec.readElf8();
int lineBase = sec.readElf8();
int lineBase = Integer.valueOf(sec.readElf8()).byteValue();
int lineRange = sec.readElf8();
int opcodeBase = sec.readElf8();
@ -153,9 +160,6 @@ public class DwarfReader implements ELFDebug {
System.out.println("Line version: " + version);
}
if (lineBase > 127) {
lineBase = lineBase - 256;
}
if (DEBUG) {
System.out.println("Line base : " + lineBase);
System.out.println("Line range : " + lineRange);
@ -179,7 +183,10 @@ public class DwarfReader implements ELFDebug {
int c;
while ((c = sec.readElf8()) != 0) {
sb.append((char)c);
while((c = sec.readElf8()) != 0) sb.append((char) c);
while((c = sec.readElf8()) != 0) {
sb.append((char) c);
}
if (DEBUG) System.out.println("Line: include file: " + sb.toString());
directories.add(sb.toString());
sb.setLength(0);
@ -191,7 +198,10 @@ public class DwarfReader implements ELFDebug {
long size = 0;
while ((c = sec.readElf8()) != 0) {
sb.append((char)c);
while((c = sec.readElf8()) != 0) sb.append((char) c);
while((c = sec.readElf8()) != 0) {
sb.append((char) c);
}
dirIndex = sec.readLEB128();
time = sec.readLEB128();
size = sec.readLEB128();
@ -201,6 +211,7 @@ public class DwarfReader implements ELFDebug {
sb.setLength(0);
}
/* Now we should have entered the position of the "code" for generating the
* line <=> address table
*/
@ -221,50 +232,57 @@ public class DwarfReader implements ELFDebug {
isBasicBlock = false;
lineData.clear();
while(!endSequence) {
int ins = sec.readElf8();
if (DEBUG) System.out.print("POS: " + sec.getPosition() + " INS: " + Utils.hex8(ins) + " ");
switch(ins) {
int opCode = sec.readElf8();
if (DEBUG) System.out.print("POS: " + sec.getPosition() + " INS: " + Utils.hex8(opCode) + " ");
switch(opCode) {
case DW_LNS_EXT:
/* extended instruction */
int len = sec.readElf8();
/* extended opcodes */
int len = (int) sec.readLEB128();
int extIns = sec.readElf8();
if (DEBUG) System.out.println("EXT: " + Utils.hex8(extIns));
switch(extIns) {
case DW_LNE_end_sequence:
endSequence = true;
lineData.add(new LineEntry(lineLine, lineAddress, lineFile));
lineAddress = 0;
lineFile = 1;
lineLine = 1;
lineColumn = 0;
isStatement = defaultIsStmt != 0;
isBasicBlock = false;
if (DEBUG) System.out.println("Line: End sequence executed!!!");
break;
case DW_LNE_define_file:
if (DEBUG) System.out.println("Line: Should define a file!!!!");
break;
case DW_LNE_set_address:
if (len == 2)
lineAddress = sec.readElf8();
if (len == 3)
lineAddress = sec.readElf16();
if (len == 5)
lineAddress = sec.readElf32();
lineAddress = sec.readElf16();
if (DEBUG) System.out.println("Line: Set address to: " + Utils.hex16(lineAddress) +
" (len: " + len + ")");
break;
case DW_LNE_define_file:
/* XXX TODO Implement me */
if (DEBUG) System.out.println("Line: Should define a file!!!!");
break;
case DW_LNE_set_discriminator: // DWARF 4.0?
/* currently just read it but ignore it - TODO: use this info */
sec.readLEB128();
break;
/*reg_discriminator = */sec.readElf8();
break;
default:
/* XXX TODO Implement me */
}
break;
case DW_LNS_copy:
/* copy data to matrix... */
if (DEBUG) System.out.println("Line: copy data (" + lineLine + "," +
Utils.hex16(lineAddress) + ") to matrix...");
lineData.add(new LineEntry(lineLine, lineAddress));
lineData.add(new LineEntry(lineLine, lineAddress, lineFile));
isBasicBlock = false;
break;
case DW_LNS_advance_pc:
long add = sec.readLEB128();
lineAddress += add * minOpLen;
lineAddress += minOpLen * add;
if (DEBUG) System.out.println("Line: Increased address to: " + Utils.hex16(lineAddress));
break;
case DW_LNS_advance_line:
@ -291,23 +309,42 @@ public class DwarfReader implements ELFDebug {
break;
case DW_LNS_const_add_pc:
if (DEBUG) System.out.println("Line: *** Should add const to PC - but how much - same as FF??");
{
int adjustedOpcode = 255 - opcodeBase;
int operationAdvance = adjustedOpcode / lineRange;
lineAddress += minOpLen * operationAdvance;
}
break;
case DW_LNS_fixed_advance_pc:
int incr = sec.readElf16();
lineAddress += incr;
if (DEBUG) System.out.println("Line: *** Increased address to: " + Utils.hex16(lineAddress));
break;
case DW_LNS_set_prologue_end:
/*reg_prologue_end = true;*/
break;
case DW_LNS_set_epilogue_begin:
/*reg_epilogue_begin = true;*/
break;
case DW_LNS_set_isa:
/*reg_isa = (int) */ sec.readLEB128();
break;
default:
if (DEBUG) {
System.out.println("INS: " + Utils.hex8(ins));
System.out.println("INS: " + Utils.hex8(opCode));
}
int lineInc = lineBase + ((ins - opcodeBase) % lineRange);
int addrInc = (ins - opcodeBase) / lineRange;
lineAddress += addrInc * minOpLen;
int adjustedOpcode = opCode - opcodeBase;
int operationAdvance = adjustedOpcode / lineRange;
int lineInc = lineBase + (adjustedOpcode % lineRange);
lineLine += lineInc;
lineData.add(new LineEntry(lineLine, lineAddress));
lineAddress += minOpLen * operationAdvance;
lineData.add(new LineEntry(lineLine, lineAddress, lineFile));
isBasicBlock = false;
if (DEBUG) System.out.println("Line: *** Special operation => addr: " +
Utils.hex16(lineAddress) + " Line: " + lineLine + " lineInc: " + lineInc);
}
@ -325,12 +362,12 @@ public class DwarfReader implements ELFDebug {
}
}
}
/* Now we have some tables of data where it should be possible to sort out which
* addresses correspond to which lines!?
*/
if (DEBUG) {
for (LineData data : lineInfo) {
System.out.println("Compiled file: " + data.sourceFiles[0]);
@ -343,7 +380,7 @@ public class DwarfReader implements ELFDebug {
}
}
}
/* DWARF - address ranges information */
private void readAranges(ELFSection sec) {
if (DEBUG) System.out.println("DWARF Aranges - ELF Section length: " + sec.getSize());
@ -386,11 +423,24 @@ public class DwarfReader implements ELFDebug {
LineData data = lineInfo.get(i);
int start = data.lineEntries[0].address;
int end = data.lineEntries[data.lineEntries.length - 1].address;
/* XXX ignore all line entries starting on address 0 */
if (start == 0) continue;
if (address <= end && address >= start) {
for (int j = 0; j < data.lineEntries.length; j++) {
if (data.lineEntries[j].address >= address) {
return new DebugInfo(data.lineEntries[j].line, null, data.sourceFiles[0], "* not available");
}
LineEntry lineEntry = data.lineEntries[j];
int startEntry = lineEntry.address;
int endEntry;
if (j+1 < data.lineEntries.length) {
endEntry = data.lineEntries[j+1].address-1;
} else {
/* do not match prologue entries */
continue;
}
if (address >= startEntry &&
address <= endEntry) {
return new DebugInfo(lineEntry.line, null, data.sourceFiles[lineEntry.file-1], "* not available");
}
}
}
}
@ -415,4 +465,51 @@ public class DwarfReader implements ELFDebug {
return sourceFilesArray;
}
public static void main(String[] args) throws Exception {
/* This method goes through all possible executable addresses, and
* generates an output comparable to that of msp430-addr2line. */
/* Example usage:
* > java se/sics/mspsim/debug/DwarfReader hello-world.sky > cmp.dwarfmspsim */
/* Example output:
* 0x00000000
* ??:0
* 0x00000001
* ??:0
* ... */
/* Comparison with msp430-addr2line output example:
* > for A in {0..65535}; do printf "%x\n" $A; done > TMP
* > cat TMP | msp430-addr2line -p -a -s -e hello-world.sky > cmp.addr2line
* > rm TMP
*
* > diff -y --suppress-common-lines cmp.addr2line cmp.dwarfmspsim */
ELF elf = ELF.readELF(args[0]);
DwarfReader dwarfReader = new DwarfReader(elf);
dwarfReader.read();
if (args.length > 1) {
int address = Integer.parseInt(args[1], 16);
DebugInfo debugInfo = dwarfReader.getDebugInfo(address);
if (debugInfo == null) {
System.out.println(String.format("0x%08x", address) + ": "
+ "??" + ":" + "0");
} else {
System.out.println(String.format("0x%08x", address) + ": "
+ new File(debugInfo.getFile()).getName() + ":" + debugInfo.getLine());
}
} else {
for (int address = 0; address <= 0xffff; address++) {
DebugInfo debugInfo = dwarfReader.getDebugInfo(address);
if (debugInfo == null) {
System.out.println(String.format("0x%08x", address) + ": "
+ "??" + ":" + "0");
} else {
System.out.println(String.format("0x%08x", address) + ": "
+ new File(debugInfo.getFile()).getName() + ":" + debugInfo.getLine());
}
}
}
}
}