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:
parent
fd074ab029
commit
d3a8e639c8
2 changed files with 96 additions and 38 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue