1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-04 06:45:43 +02:00

use mapping of sections for dwarf parser rather than allocating memory which avoids out of memory exceptions for large symbol files.

This commit is contained in:
Warren Paul 2009-04-03 15:57:29 +00:00
parent f0893c8b81
commit 7ef8d28991
3 changed files with 146 additions and 177 deletions

View file

@ -11,10 +11,9 @@
package org.eclipse.cdt.utils.debug.dwarf;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -160,7 +159,7 @@ public class Dwarf {
int identifierCase;
}
Map<String, byte[]> dwarfSections = new HashMap<String, byte[]>();
Map<String, ByteBuffer> dwarfSections = new HashMap<String, ByteBuffer>();
Map<Integer, Map<Long, AbbreviationEntry>> abbreviationMaps = new HashMap<Integer, Map<Long, AbbreviationEntry>>();
boolean isLE;
@ -188,113 +187,105 @@ public class Dwarf {
String name = section.toString();
for (String element : DWARF_SCNNAMES) {
if (name.equals(element)) {
dwarfSections.put(element, section.loadSectionData());
try {
dwarfSections.put(element, section.mapSectionData());
} catch (Exception e) {
e.printStackTrace();
CCorePlugin.log(e);
}
}
}
}
}
int read_4_bytes(InputStream in) throws IOException {
int read_4_bytes(ByteBuffer in) throws IOException {
try {
byte[] bytes = new byte[4];
int n = in.read(bytes, 0, bytes.length);
if (n != 4) {
throw new IOException(CCorePlugin.getResourceString("Util.exception.missingBytes")); //$NON-NLS-1$
}
return read_4_bytes(bytes, 0);
} catch (IndexOutOfBoundsException e) {
in.get(bytes);
return read_4_bytes(bytes);
} catch (Exception e) {
throw new IOException(CCorePlugin.getResourceString("Util.exception.missingBytes")); //$NON-NLS-1$
}
}
// FIXME:This is wrong, it's signed.
int read_4_bytes(byte[] bytes, int offset) throws IndexOutOfBoundsException {
int read_4_bytes(byte[] bytes) throws IndexOutOfBoundsException {
if (isLE) {
return (
((bytes[offset + 3] & 0xff) << 24)
| ((bytes[offset + 2] & 0xff) << 16)
| ((bytes[offset + 1] & 0xff) << 8)
| (bytes[offset] & 0xff));
((bytes[3] & 0xff) << 24)
| ((bytes[2] & 0xff) << 16)
| ((bytes[1] & 0xff) << 8)
| (bytes[0] & 0xff));
}
return (
((bytes[offset] & 0xff) << 24)
| ((bytes[offset + 1] & 0xff) << 16)
| ((bytes[offset + 2] & 0xff) << 8)
| (bytes[offset + 3] & 0xff));
((bytes[0] & 0xff) << 24)
| ((bytes[1] & 0xff) << 16)
| ((bytes[2] & 0xff) << 8)
| (bytes[3] & 0xff));
}
long read_8_bytes(InputStream in) throws IOException {
long read_8_bytes(ByteBuffer in) throws IOException {
try {
byte[] bytes = new byte[8];
int n = in.read(bytes, 0, bytes.length);
if (n != 8) {
throw new IOException(CCorePlugin.getResourceString("Util.exception.missingBytes")); //$NON-NLS-1$
}
return read_8_bytes(bytes, 0);
} catch (IndexOutOfBoundsException e) {
in.get(bytes);
return read_8_bytes(bytes);
} catch (Exception e) {
throw new IOException(CCorePlugin.getResourceString("Util.exception.missingBytes")); //$NON-NLS-1$
}
}
// FIXME:This is wrong, for unsigned.
long read_8_bytes(byte[] bytes, int offset) throws IndexOutOfBoundsException {
long read_8_bytes(byte[] bytes) throws IndexOutOfBoundsException {
if (isLE) {
return (((bytes[offset + 7] & 0xff) << 56)
| ((bytes[offset + 6] & 0xff) << 48)
| ((bytes[offset + 5] & 0xff) << 40)
| ((bytes[offset + 4] & 0xff) << 32)
| ((bytes[offset + 3] & 0xff) << 24)
| ((bytes[offset + 2] & 0xff) << 16)
| ((bytes[offset + 1] & 0xff) << 8)
| (bytes[offset] & 0xff));
return (((bytes[7] & 0xff) << 56)
| ((bytes[6] & 0xff) << 48)
| ((bytes[5] & 0xff) << 40)
| ((bytes[4] & 0xff) << 32)
| ((bytes[3] & 0xff) << 24)
| ((bytes[2] & 0xff) << 16)
| ((bytes[1] & 0xff) << 8)
| (bytes[0] & 0xff));
}
return (((bytes[offset] & 0xff) << 56)
| ((bytes[offset + 1] & 0xff) << 48)
| ((bytes[offset + 2] & 0xff) << 40)
| ((bytes[offset + 3] & 0xff) << 32)
| ((bytes[offset + 4] & 0xff) << 24)
| ((bytes[offset + 5] & 0xff) << 16)
| ((bytes[offset + 6] & 0xff) << 8)
| (bytes[offset] & 0xff));
return (((bytes[0] & 0xff) << 56)
| ((bytes[1] & 0xff) << 48)
| ((bytes[2] & 0xff) << 40)
| ((bytes[3] & 0xff) << 32)
| ((bytes[4] & 0xff) << 24)
| ((bytes[5] & 0xff) << 16)
| ((bytes[6] & 0xff) << 8)
| (bytes[7] & 0xff));
}
short read_2_bytes(InputStream in) throws IOException {
short read_2_bytes(ByteBuffer in) throws IOException {
try {
byte[] bytes = new byte[2];
int n = in.read(bytes, 0, bytes.length);
if (n != 2) {
throw new IOException(CCorePlugin.getResourceString("Util.exception.missingBytes")); //$NON-NLS-1$
}
return read_2_bytes(bytes, 0);
} catch (IndexOutOfBoundsException e) {
in.get(bytes);
return read_2_bytes(bytes);
} catch (Exception e) {
throw new IOException(CCorePlugin.getResourceString("Util.exception.missingBytes")); //$NON-NLS-1$
}
}
short read_2_bytes(byte[] bytes, int offset) throws IndexOutOfBoundsException {
short read_2_bytes(byte[] bytes) throws IndexOutOfBoundsException {
if (isLE) {
return (short) (((bytes[offset + 1] & 0xff) << 8) + (bytes[offset] & 0xff));
return (short) (((bytes[1] & 0xff) << 8) + (bytes[0] & 0xff));
}
return (short) (((bytes[offset] & 0xff) << 8) + (bytes[offset + 1] & 0xff));
return (short) (((bytes[0] & 0xff) << 8) + (bytes[1] & 0xff));
}
private int num_leb128_read;
/* unsigned */
long read_unsigned_leb128(InputStream in) throws IOException {
long read_unsigned_leb128(ByteBuffer in) throws IOException {
/* unsigned */
long result = 0;
num_leb128_read = 0;
int shift = 0;
short b;
while (true) {
b = (short) in.read();
if (b == -1)
b = in.get();
if (!in.hasRemaining())
break; //throw new IOException("no more data");
num_leb128_read++;
result |= ((long) (b & 0x7f) << shift);
if ((b & 0x80) == 0) {
break;
@ -305,19 +296,17 @@ public class Dwarf {
}
/* unsigned */
long read_signed_leb128(InputStream in) throws IOException {
long read_signed_leb128(ByteBuffer in) throws IOException {
/* unsigned */
long result = 0;
int shift = 0;
int size = 32;
num_leb128_read = 0;
short b;
while (true) {
b = (short) in.read();
if (b == -1)
b = in.get();
if (!in.hasRemaining())
throw new IOException(CCorePlugin.getResourceString("Util.exception.noData")); //$NON-NLS-1$
num_leb128_read++;
result |= ((long) (b & 0x7f) << shift);
shift += 7;
if ((b & 0x80) == 0) {
@ -335,28 +324,30 @@ public class Dwarf {
}
void parseDebugInfo(IDebugEntryRequestor requestor) {
byte[] data = dwarfSections.get(DWARF_DEBUG_INFO);
ByteBuffer data = dwarfSections.get(DWARF_DEBUG_INFO);
if (data != null) {
try {
int length = 0;
for (int offset = 0; offset < data.length; offset += (length + 4)) {
while (data.hasRemaining()) {
CompilationUnitHeader header = new CompilationUnitHeader();
header.length = length = read_4_bytes(data, offset);
header.version = read_2_bytes(data, offset + 4);
header.abbreviationOffset = read_4_bytes(data, offset + 6);
header.addressSize = data[offset + 10];
header.length = read_4_bytes(data);
header.version = read_2_bytes(data);
header.abbreviationOffset = read_4_bytes(data);
header.addressSize = data.get();
if (printEnabled) {
System.out.println("Compilation Unit @ " + Long.toHexString(offset)); //$NON-NLS-1$
System.out.println("Compilation Unit @ " + Long.toHexString(data.position())); //$NON-NLS-1$
System.out.println(header);
}
// read the abbrev section.
// Note "length+4" is the total size in bytes of the CU data.
InputStream in = new ByteArrayInputStream(data, offset + 11, length+4-11);
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header);
parseDebugInfoEntry(requestor, in, abbrevs, header);
// Note "length+4" is the total size in bytes of the CU data.
ByteBuffer entryBuffer = data.slice();
entryBuffer.limit(header.length + 4 - 11);
parseDebugInfoEntry(requestor, entryBuffer, abbrevs, header);
data.position(data.position() + header.length + 4 - 11);
if (printEnabled)
System.out.println();
}
@ -367,23 +358,21 @@ public class Dwarf {
}
Map<Long, AbbreviationEntry> parseDebugAbbreviation(CompilationUnitHeader header) throws IOException {
int offset = header.abbreviationOffset;
Integer key = new Integer(offset);
Integer key = new Integer(header.abbreviationOffset);
Map<Long, AbbreviationEntry> abbrevs = abbreviationMaps.get(key);
if (abbrevs == null) {
abbrevs = new HashMap<Long, AbbreviationEntry>();
abbreviationMaps.put(key, abbrevs);
byte[] data = dwarfSections.get(DWARF_DEBUG_ABBREV);
ByteBuffer data = dwarfSections.get(DWARF_DEBUG_ABBREV);
if (data != null) {
InputStream in = new ByteArrayInputStream(data);
in.skip(offset);
while (in.available() > 0) {
long code = read_unsigned_leb128(in);
data.position(header.abbreviationOffset);
while (data.remaining() > 0) {
long code = read_unsigned_leb128(data);
if (code == 0) {
break;
}
long tag = read_unsigned_leb128(in);
byte hasChildren = (byte) in.read();
long tag = read_unsigned_leb128(data);
byte hasChildren = data.get();
AbbreviationEntry entry = new AbbreviationEntry(code, tag, hasChildren);
//System.out.println("\tAbrev Entry: " + code + " " + Long.toHexString(entry.tag) + " " + entry.hasChildren);
@ -392,8 +381,8 @@ public class Dwarf {
long name = 0;
long form = 0;
do {
name = read_unsigned_leb128(in);
form = read_unsigned_leb128(in);
name = read_unsigned_leb128(data);
form = read_unsigned_leb128(data);
if (name != 0) {
entry.attributes.add(new Attribute(name, form));
}
@ -406,9 +395,9 @@ public class Dwarf {
return abbrevs;
}
void parseDebugInfoEntry(IDebugEntryRequestor requestor, InputStream in, Map<Long, AbbreviationEntry> abbrevs, CompilationUnitHeader header)
void parseDebugInfoEntry(IDebugEntryRequestor requestor, ByteBuffer in, Map<Long, AbbreviationEntry> abbrevs, CompilationUnitHeader header)
throws IOException {
while (in.available() > 0) {
while (in.remaining() > 0) {
long code = read_unsigned_leb128(in);
AbbreviationEntry entry = abbrevs.get(new Long(code));
if (entry != null) {
@ -428,7 +417,7 @@ public class Dwarf {
}
}
Object readAttribute(int form, InputStream in, CompilationUnitHeader header) throws IOException {
Object readAttribute(int form, ByteBuffer in, CompilationUnitHeader header) throws IOException {
Object obj = null;
switch (form) {
case DwarfConstants.DW_FORM_addr :
@ -440,16 +429,16 @@ public class Dwarf {
{
int size = (int) read_unsigned_leb128(in);
byte[] bytes = new byte[size];
in.read(bytes, 0, size);
in.get(bytes);
obj = bytes;
}
break;
case DwarfConstants.DW_FORM_block1 :
{
int size = in.read();
int size = in.get();
byte[] bytes = new byte[size];
in.read(bytes, 0, size);
in.get(bytes);
obj = bytes;
}
break;
@ -458,7 +447,7 @@ public class Dwarf {
{
int size = read_2_bytes(in);
byte[] bytes = new byte[size];
in.read(bytes, 0, size);
in.get(bytes);
obj = bytes;
}
break;
@ -467,13 +456,13 @@ public class Dwarf {
{
int size = read_4_bytes(in);
byte[] bytes = new byte[size];
in.read(bytes, 0, size);
in.get(bytes);
obj = bytes;
}
break;
case DwarfConstants.DW_FORM_data1 :
obj = new Byte((byte) in.read());
obj = new Byte(in.get());
break;
case DwarfConstants.DW_FORM_data2 :
@ -500,7 +489,7 @@ public class Dwarf {
{
int c;
StringBuffer sb = new StringBuffer();
while ((c = in.read()) != -1) {
while ((c = in.get()) != -1) {
if (c == 0) {
break;
}
@ -511,21 +500,22 @@ public class Dwarf {
break;
case DwarfConstants.DW_FORM_flag :
obj = new Byte((byte) in.read());
obj = new Byte(in.get());
break;
case DwarfConstants.DW_FORM_strp :
{
int offset = read_4_bytes(in);
byte[] data = dwarfSections.get(DWARF_DEBUG_STR);
ByteBuffer data = dwarfSections.get(DWARF_DEBUG_STR);
if (data == null) {
obj = new String();
} else if (offset < 0 || offset > data.length) {
} else if (offset < 0 || offset > data.capacity()) {
obj = new String();
} else {
StringBuffer sb = new StringBuffer();
for (; offset < data.length; offset++) {
byte c = data[offset];
data.position(offset);
while (data.hasRemaining()) {
byte c = data.get();
if (c == 0) {
break;
}
@ -537,7 +527,7 @@ public class Dwarf {
break;
case DwarfConstants.DW_FORM_ref1 :
obj = new Byte((byte) in.read());
obj = new Byte(in.get());
break;
case DwarfConstants.DW_FORM_ref2 :
@ -647,7 +637,7 @@ public class Dwarf {
}
}
Long readAddress(InputStream in, CompilationUnitHeader header) throws IOException {
Long readAddress(ByteBuffer in, CompilationUnitHeader header) throws IOException {
long value = 0;
switch (header.addressSize) {

View file

@ -14,10 +14,12 @@ package org.eclipse.cdt.utils.debug.dwarf;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ISymbolReader;
import org.eclipse.cdt.utils.debug.IDebugEntryRequestor;
import org.eclipse.cdt.utils.elf.Elf;
@ -45,7 +47,6 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
private String m_exeFileWin32Drive; // Win32 drive of the exe file.
private boolean m_onWindows;
private boolean m_parsed = false;
private int m_leb128Size = 0;
private ArrayList<Integer> m_parsedLineTableOffsets = new ArrayList<Integer>();
private int m_parsedLineTableSize = 0;
@ -77,9 +78,10 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
// problem itself, but will at least continue to load the other
// sections.
try {
dwarfSections.put(element, section.loadSectionData());
} catch (OutOfMemoryError e) {
// Don't log this error, handle it silently without any UI.
dwarfSections.put(element, section.mapSectionData());
} catch (Exception e) {
e.printStackTrace();
CCorePlugin.log(e);
}
}
}
@ -104,10 +106,10 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
String cuCompDir, // compilation directory of the CU
int cuStmtList) // offset of the CU line table in .debug_line section
{
byte[] data = dwarfSections.get(DWARF_DEBUG_LINE);
ByteBuffer data = dwarfSections.get(DWARF_DEBUG_LINE);
if (data != null) {
try {
int offset = cuStmtList;
data.position(cuStmtList);
/* Read line table header:
*
@ -127,7 +129,7 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
if (! m_parsedLineTableOffsets.contains(cuOffset)) {
m_parsedLineTableOffsets.add(cuOffset);
int length = read_4_bytes(data, offset) + 4;
int length = read_4_bytes(data) + 4;
m_parsedLineTableSize += length + 4;
}
else {
@ -137,9 +139,9 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
}
// Skip the following till "opcode_base"
offset = offset + 14;
int opcode_base = data[offset++];
offset += opcode_base - 1;
data.position(data.position() + 10);
int opcode_base = data.get();
data.position(data.position() + opcode_base - 1);
// Read in directories.
//
@ -151,38 +153,32 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
String str, fileName;
while (true) {
str = readString(data, offset);
str = readString(data);
if (str.length() == 0)
break;
dirList.add(str);
offset += str.length()+1;
}
offset++;
// Read file names
//
long leb128;
while (true) {
fileName = readString(data, offset);
fileName = readString(data);
if (fileName.length() == 0) // no more file entry
break;
offset += fileName.length()+1;
// dir index
leb128 = read_unsigned_leb128(data, offset);
offset += m_leb128Size;
leb128 = read_unsigned_leb128(data);
addSourceFile(dirList.get((int)leb128), fileName);
// Skip the followings
//
// modification time
leb128 = read_unsigned_leb128(data, offset);
offset += m_leb128Size;
leb128 = read_unsigned_leb128(data);
// file size in bytes
leb128 = read_unsigned_leb128(data, offset);
offset += m_leb128Size;
leb128 = read_unsigned_leb128(data);
}
} catch (IOException e) {
e.printStackTrace();
@ -200,11 +196,11 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
*/
private void getSourceFilesFromDebugLineSection()
{
byte[] data = dwarfSections.get(DWARF_DEBUG_LINE);
ByteBuffer data = dwarfSections.get(DWARF_DEBUG_LINE);
if (data == null)
return;
int sectionSize = data.length;
int sectionSize = data.capacity();
int minHeaderSize = 16;
// Check if there is data in .debug_line section that is not parsed
@ -233,13 +229,13 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
try {
while (lineTableStart < sectionSize - minHeaderSize) {
int offset = lineTableStart;
data.position(lineTableStart);
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, offset);
int tableLength = read_4_bytes(data);
// Record start of next CU line table
lineTableStart += tableLength + 4;
@ -256,9 +252,12 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
if (lineTableStart < sectionSize - minHeaderSize &&
(lineTableStart & 0x3) != 0)
{
int ltLength = read_4_bytes(data, lineTableStart);
int dwarfVer = read_2_bytes(data, lineTableStart+4);
int minInstLengh = data[lineTableStart+4+2+4];
int savedPosition = data.position();
data.position(lineTableStart);
int ltLength = read_4_bytes(data);
int dwarfVer = read_2_bytes(data);
int minInstLengh = data.get(data.position() + 4);
boolean dataValid =
ltLength > minHeaderSize &&
@ -268,6 +267,8 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
if (! dataValid) // padding exists !
lineTableStart = (lineTableStart+3) & ~0x3;
data.position(savedPosition);
}
if (m_parsedLineTableOffsets.contains(currLineTableStart))
@ -275,9 +276,9 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
continue;
// Skip following fields till "opcode_base"
offset = offset + 14;
int opcode_base = data[offset++];
offset += opcode_base - 1;
data.position(data.position() + 10);
int opcode_base = data.get();
data.position(data.position() + opcode_base - 1);
// Read in directories.
//
@ -289,38 +290,32 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
dirList.add(""); //$NON-NLS-1$
while (true) {
str = readString(data, offset);
str = readString(data);
if (str.length() == 0)
break;
dirList.add(str);
offset += str.length() + 1;
}
offset++;
// Read file names
//
long leb128;
while (true) {
fileName = readString(data, offset);
fileName = readString(data);
if (fileName.length() == 0) // no more file entry
break;
offset += fileName.length() + 1;
// dir index. Note "0" is reserved for compilation directory.
leb128 = read_unsigned_leb128(data, offset);
offset += m_leb128Size;
leb128 = read_unsigned_leb128(data);
addSourceFile(dirList.get((int) leb128), fileName);
// Skip the followings
//
// modification time
leb128 = read_unsigned_leb128(data, offset);
offset += m_leb128Size;
leb128 = read_unsigned_leb128(data);
// file size in bytes
leb128 = read_unsigned_leb128(data, offset);
offset += m_leb128Size;
leb128 = read_unsigned_leb128(data);
}
}
} catch (IOException e) {
@ -400,17 +395,16 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
}
/**
* Read a null-ended string from the given "data" stream starting at the given "offset".
* data : IN, byte stream
* offset: IN, offset in the stream
* Read a null-ended string from the given "data" stream.
* data : IN, byte buffer
*/
String readString(byte[] data, int offset)
String readString(ByteBuffer data)
{
String str;
StringBuffer sb = new StringBuffer();
for (; offset < data.length; offset++) {
byte c = data[offset];
while (data.hasRemaining()) {
byte c = data.get();
if (c == 0) {
break;
}
@ -420,30 +414,6 @@ public class DwarfReader extends Dwarf implements ISymbolReader {
str = sb.toString();
return str;
}
// Note this method modifies a data member
//
long read_unsigned_leb128(byte[] data, int offset) throws IOException {
/* unsigned */
long result = 0;
int shift = 0;
short b;
m_leb128Size = 0;
while (true) {
b = data[offset++];
if (data.length == offset)
break; //throw new IOException("no more data");
m_leb128Size++;
result |= ((long) (b & 0x7f) << shift);
if ((b & 0x80) == 0) {
break;
}
shift += 7;
}
return result;
}
// Override parent: only handle TAG_Compile_Unit.
@Override

View file

@ -13,6 +13,8 @@ package org.eclipse.cdt.utils.elf;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -333,6 +335,10 @@ public class Elf {
public long sh_addralign;
public long sh_entsize;
public ByteBuffer mapSectionData() throws IOException {
return efile.getChannel().map(MapMode.READ_ONLY, sh_offset, sh_size).load().asReadOnlyBuffer();
}
public byte[] loadSectionData() throws IOException {
byte[] data = new byte[(int)sh_size];
efile.seek(sh_offset);
@ -943,6 +949,9 @@ public class Elf {
if (efile != null) {
efile.close();
efile = null;
// ensure the mappings get cleaned up
System.gc();
}
} catch (IOException e) {
}