1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Bug 425955: NPE in DwarfReader

- Fix parsing .debug_line section in version format, part of Dwarf 4.
- Refactor in a separate method reading initial length field to
consistently handle 64-bit dwarf format

Change-Id: I9f32862ed91540c24ce33227eeb384a5d6b141da
Signed-off-by: Teodor Madan <teodor.madan@freescale.com>
Reviewed-on: https://git.eclipse.org/r/20830
This commit is contained in:
Teodor Madan 2014-01-17 14:22:36 +02:00
parent fd074ab029
commit d3a8e639c8
2 changed files with 96 additions and 38 deletions

View file

@ -372,19 +372,15 @@ public class Dwarf {
try {
while (data.hasRemaining()) {
CompilationUnitHeader header = new CompilationUnitHeader();
header.length = read_4_bytes(data) & 0xffffffffL;
if (header.length == 0xffffffffL) {
header.length = read_8_bytes(data);
header.offsetSize = 8;
} else if (header.length == 0) { // IRIX
header.length = read_8_bytes(data);
header.offsetSize = 8;
} else
header.offsetSize = 4;
InitialLengthValue sectionLength = readInitialLengthField(data);
header.length = sectionLength.length;
header.offsetSize = sectionLength.offsetSize;
header.version = read_2_bytes(data);
header.abbreviationOffset = read_4_bytes(data);
if (header.offsetSize == 8)
header.abbreviationOffset = (int)read_8_bytes(data);
else
header.abbreviationOffset = read_4_bytes(data);
header.addressSize = data.get();
if (printEnabled) {
@ -394,12 +390,13 @@ public class Dwarf {
// read the abbrev section.
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header);
// Note "length+4" is the total size in bytes of the CU data.
// A 4-byte or 12-byte unsigned integer representing the length of the .debug_info
// contribution for that compilation unit, not including the length field itself.
ByteBuffer entryBuffer = data.slice();
entryBuffer.limit(((int) header.length) + 4 - 11);
entryBuffer.limit(((int)header.length) - (header.offsetSize == 8 ? 11 : 7));
parseDebugInfoEntry(requestor, entryBuffer, abbrevs, header);
data.position(data.position() + ((int) header.length) + 4 - 11);
data.position(data.position() + ((int)header.length) - (header.offsetSize == 8 ? 11 : 7));
if (printEnabled)
System.out.println();
@ -410,6 +407,44 @@ public class Dwarf {
}
}
/**
*
*/
class InitialLengthValue {
/**
* section length
*/
long length;
/**
* section offset size in bytes.
*/
byte offsetSize; //
}
/**
* Read section length field from the beginning of dwarf section.
*
* <p>See Chapter 7.4 32-Bit and 64-Bit DWARF Formats</p>
* @param data - byte buffer positioned at the start of section length record
* @return section length info. Cannot be null.
* @throws IOException
*/
InitialLengthValue readInitialLengthField(ByteBuffer data) throws IOException {
InitialLengthValue info = new InitialLengthValue();
info.length = read_4_bytes(data) & 0xffffffffL;
if (info.length == 0xffffffffL) {
info.length = read_8_bytes(data);
info.offsetSize = 8;
} else if (info.length == 0) { // IRIX
info.length = read_8_bytes(data);
info.offsetSize = 8;
} else
info.offsetSize = 4;
return info;
}
Map<Long, AbbreviationEntry> parseDebugAbbreviation(CompilationUnitHeader header) throws IOException {
Integer key = new Integer(header.abbreviationOffset);
Map<Long, AbbreviationEntry> abbrevs = abbreviationMaps.get(key);

View file

@ -50,7 +50,7 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
private String[] m_fileNames = null;
private boolean m_parsed = false;
private final ArrayList<Integer> m_parsedLineTableOffsets = new ArrayList<Integer>();
private int m_parsedLineTableSize = 0;
private long m_parsedLineTableSize = 0;
public DwarfReader(String file) throws IOException {
super(file);
@ -143,10 +143,11 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
/* Read line table header:
*
* total_length: 4 bytes (excluding itself)
* total_length: 4/12 bytes (excluding itself)
* version: 2
* prologue length: 4
* prologue length: 4/8 bytes (depending on section version)
* minimum_instruction_len: 1
* maximum_operations_per_instruction 1 - it is defined for version >= 4
* default_is_stmt: 1
* line_base: 1
* line_range: 1
@ -156,20 +157,30 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
// Remember the CU line tables we've parsed.
Integer cuOffset = new Integer(cuStmtList);
boolean dwarf64Bit = false;
if (! m_parsedLineTableOffsets.contains(cuOffset)) {
m_parsedLineTableOffsets.add(cuOffset);
int length = read_4_bytes(data) + 4;
m_parsedLineTableSize += length + 4;
// Note the length does not including the "length" field(s) itself.
InitialLengthValue length = readInitialLengthField(data);
dwarf64Bit = length.offsetSize == 8;
m_parsedLineTableSize += length.length + (dwarf64Bit ? 12 : 4);
}
else {
// Compiler like ARM RVCT may produce several CUs for the
// same source files.
return;
}
short version = read_2_bytes(data);
// Skip the following till "opcode_base"
data.position(data.position() + 10);
short skip_bytes = 8;
if (version >= 4)
skip_bytes += 1; // see maximum_operations_per_instruction
if (dwarf64Bit)
skip_bytes += 4; // see prologue length for 64-bit DWARF format
data.position(data.position() + skip_bytes);
int opcode_base = data.get();
data.position(data.position() + opcode_base - 1);
@ -248,16 +259,16 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
/*
* Line table header for one compile_unit:
*
* total_length: 4 bytes (excluding itself)
* version: 2
* prologue length: 4
* total_length: 4/12 bytes (excluding itself)
* version: 2
* prologue length: 4/8 bytes (depending on section version)
* minimum_instruction_len: 1
* default_is_stmt: 1
* line_base: 1
* line_range: 1
* opcode_base: 1
* standard_opcode_lengths: (value of opcode_base)
*/
* maximum_operations_per_instruction 1 - it is defined for version >= 4
* default_is_stmt: 1
* line_base: 1
* line_range: 1
* opcode_base: 1
* standard_opcode_lengths: (value of opcode_base) */
int lineTableStart = 0; // offset in the .debug_line section
@ -268,11 +279,15 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
Integer currLineTableStart = new Integer(lineTableStart);
// Read length of the line table for one compile unit
// Note the length does not including the "length" field itself.
int tableLength = read_4_bytes(data);
// Note the length does not including the "length" field(s) itself.
InitialLengthValue sectionLength = readInitialLengthField(data);
// Record start of next CU line table
lineTableStart += tableLength + 4;
boolean dwarf64Bit = sectionLength.offsetSize == 8;
lineTableStart += (int)(sectionLength.length + (dwarf64Bit ? 12 : 4));
m_parsedLineTableSize += sectionLength.length + (dwarf64Bit ? 12 : 4);
// According to Dwarf standard, the "tableLength" should cover the
// the whole CU line table. But some compilers (e.g. ARM RVCT 2.2)
@ -289,14 +304,15 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
int savedPosition = data.position();
data.position(lineTableStart);
int ltLength = read_4_bytes(data);
long ltLength = dwarf64Bit ? read_8_bytes(data) : read_4_bytes(data);
int dwarfVer = read_2_bytes(data);
int minInstLengh = data.get(data.position() + 4);
int minInstLengh = data.get(data.position() + (dwarf64Bit ? 8 : 4));
boolean dataValid =
ltLength > minHeaderSize &&
ltLength < 16*64*1024 && // One source file has that much line data ?
dwarfVer > 0 && dwarfVer < 4 && // ver 3 is still draft at present.
dwarfVer > 0 && dwarfVer < 5 && // ver 5 is still draft at present.
minInstLengh > 0 && minInstLengh <= 8;
if (! dataValid) // padding exists !
@ -309,8 +325,15 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
// current line table has already been parsed, skip it.
continue;
short version = read_2_bytes(data);
// Skip following fields till "opcode_base"
data.position(data.position() + 10);
short skip_bytes = 8;
if (version >= 4)
skip_bytes += 1; // see maximum_operations_per_instruction
if (dwarf64Bit)
skip_bytes += 4; // see prologue length for 64-bit DWARF format
data.position(data.position() + skip_bytes);
int opcode_base = data.get();
data.position(data.position() + opcode_base - 1);