mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
commiting partial patch from ken.ryall@nokia.com for bug #39640 adding ISymbolReader to binary model
This commit is contained in:
parent
3502da3b30
commit
06a50c17f7
9 changed files with 699 additions and 21 deletions
|
@ -12,25 +12,30 @@ package org.eclipse.cdt.internal.core.model;
|
||||||
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.ISymbolReader;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryExecutable;
|
import org.eclipse.cdt.core.IBinaryParser.IBinaryExecutable;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
|
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryShared;
|
import org.eclipse.cdt.core.IBinaryParser.IBinaryShared;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
|
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
|
||||||
import org.eclipse.cdt.core.model.CModelException;
|
import org.eclipse.cdt.core.model.CModelException;
|
||||||
|
import org.eclipse.cdt.core.model.CoreModel;
|
||||||
import org.eclipse.cdt.core.model.IBinary;
|
import org.eclipse.cdt.core.model.IBinary;
|
||||||
import org.eclipse.cdt.core.model.IBuffer;
|
import org.eclipse.cdt.core.model.IBuffer;
|
||||||
import org.eclipse.cdt.core.model.ICElement;
|
import org.eclipse.cdt.core.model.ICElement;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.ResourcesPlugin;
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.IProgressMonitor;
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
|
|
||||||
public class Binary extends Openable implements IBinary {
|
public class Binary extends Openable implements IBinary {
|
||||||
|
|
||||||
|
@ -240,24 +245,97 @@ public class Binary extends Openable implements IBinary {
|
||||||
Map hash = new HashMap();
|
Map hash = new HashMap();
|
||||||
IBinaryObject obj = getBinaryObject();
|
IBinaryObject obj = getBinaryObject();
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
ISymbol[] symbols = obj.getSymbols();
|
// First check if we can get the list of source
|
||||||
for (int i = 0; i < symbols.length; i++) {
|
// files used to build the binary from the symbol
|
||||||
switch (symbols[i].getType()) {
|
// information. if not, fall back on information from the binary parser.
|
||||||
case ISymbol.FUNCTION :
|
if (!addSourceFiles(info, obj, hash))
|
||||||
addFunction(info, symbols[i], hash);
|
{
|
||||||
break;
|
ISymbol[] symbols = obj.getSymbols();
|
||||||
|
for (int i = 0; i < symbols.length; i++) {
|
||||||
|
switch (symbols[i].getType()) {
|
||||||
|
case ISymbol.FUNCTION :
|
||||||
|
addFunction(info, symbols[i], hash);
|
||||||
|
break;
|
||||||
|
|
||||||
case ISymbol.VARIABLE :
|
case ISymbol.VARIABLE :
|
||||||
addVariable(info, symbols[i], hash);
|
addVariable(info, symbols[i], hash);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean addSourceFiles(OpenableInfo info, IBinaryObject obj,
|
||||||
|
Map hash) throws CModelException {
|
||||||
|
// Try to get the list of source files used to build the binary from the
|
||||||
|
// symbol information.
|
||||||
|
|
||||||
|
ISymbolReader symbolreader = (ISymbolReader)obj.getAdapter(ISymbolReader.class);
|
||||||
|
if (symbolreader == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String[] sourceFiles = symbolreader.getSourceFiles();
|
||||||
|
if (sourceFiles != null && sourceFiles.length > 0) {
|
||||||
|
for (int i = 0; i < sourceFiles.length; i++) {
|
||||||
|
String filename = sourceFiles[i];
|
||||||
|
|
||||||
|
// Sometimes the path in the symbolics will have a different
|
||||||
|
// case than the actual file system path. Even if the file
|
||||||
|
// system is not case sensitive this will confuse the Path
|
||||||
|
// class.
|
||||||
|
// So make sure the path is canonical, otherwise breakpoints
|
||||||
|
// won't be resolved, etc..
|
||||||
|
|
||||||
|
File file = new File(filename);
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
filename = file.getCanonicalPath();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if this source file is already in the project.
|
||||||
|
// We check this to determine if we should create a TranslationUnit or ExternalTranslationUnit
|
||||||
|
IFile sourceFile = getCProject().getProject().getFile(filename);
|
||||||
|
IPath path = new Path(filename);
|
||||||
|
|
||||||
|
IFile wkspFile = null;
|
||||||
|
if (sourceFile.exists())
|
||||||
|
wkspFile = sourceFile;
|
||||||
|
else {
|
||||||
|
IFile[] filesInWP = ResourcesPlugin
|
||||||
|
.getWorkspace().getRoot()
|
||||||
|
.findFilesForLocation(path);
|
||||||
|
|
||||||
|
for (int j = 0; j < filesInWP.length; j++) {
|
||||||
|
if (filesInWP[j].isAccessible()) {
|
||||||
|
wkspFile = filesInWP[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a translation unit for this file and add it as a child of the binary
|
||||||
|
String id = CoreModel.getRegistedContentTypeId(sourceFile
|
||||||
|
.getProject(), sourceFile.getName());
|
||||||
|
|
||||||
|
TranslationUnit tu;
|
||||||
|
if (wkspFile != null)
|
||||||
|
tu = new TranslationUnit(this, wkspFile, id);
|
||||||
|
else
|
||||||
|
tu = new ExternalTranslationUnit(this, path, id);
|
||||||
|
|
||||||
|
info.addChild(tu);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void addFunction(OpenableInfo info, ISymbol symbol, Map hash) throws CModelException {
|
private void addFunction(OpenableInfo info, ISymbol symbol, Map hash) throws CModelException {
|
||||||
IPath filename = filename = symbol.getFilename();
|
IPath filename = filename = symbol.getFilename();
|
||||||
BinaryFunction function = null;
|
BinaryFunction function = null;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006 Nokia and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Nokia - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reader that's able to decipher debug symbol formats.
|
||||||
|
*
|
||||||
|
* This initial version only returns a list of source files.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ISymbolReader {
|
||||||
|
|
||||||
|
String[] getSourceFiles();
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006 Nokia and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Nokia - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.utils.coff;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.ISymbolReader;
|
||||||
|
|
||||||
|
public class CodeViewReader implements ISymbolReader {
|
||||||
|
|
||||||
|
RandomAccessFile file;
|
||||||
|
int cvData;
|
||||||
|
boolean isLe;
|
||||||
|
List fileList;
|
||||||
|
String[] files = null;
|
||||||
|
boolean parsed = false;
|
||||||
|
|
||||||
|
public CodeViewReader(RandomAccessFile accessFile, int dataOffset, boolean littleEndian) {
|
||||||
|
file = accessFile;
|
||||||
|
cvData = dataOffset;
|
||||||
|
isLe = littleEndian;
|
||||||
|
|
||||||
|
fileList = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getSourceFiles() {
|
||||||
|
if (!parsed) {
|
||||||
|
try {
|
||||||
|
parse();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
|
||||||
|
files = new String[fileList.size()];
|
||||||
|
for (int i = 0; i < fileList.size(); i++) {
|
||||||
|
files[i] = (String)fileList.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getInt(int value) {
|
||||||
|
if (isLe) {
|
||||||
|
int tmp = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
tmp <<= 8;
|
||||||
|
tmp |= value & 0xFF;
|
||||||
|
value >>= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private short getShort(short value) {
|
||||||
|
if (isLe) {
|
||||||
|
short tmp = value;
|
||||||
|
|
||||||
|
tmp &= 0xFF;
|
||||||
|
tmp <<= 8;
|
||||||
|
tmp |= (value >> 8) & 0xFF;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse() throws IOException {
|
||||||
|
if (cvData <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// seek to the start of the CodeView data
|
||||||
|
file.seek(cvData);
|
||||||
|
|
||||||
|
// skip the next four bytes - signature "NB11"
|
||||||
|
file.skipBytes(4);
|
||||||
|
|
||||||
|
// get the offset to the subsection directory
|
||||||
|
int subsectionDirOffset = getInt(file.readInt());
|
||||||
|
|
||||||
|
// seek to the start of the subsection directory
|
||||||
|
file.seek(cvData + subsectionDirOffset);
|
||||||
|
|
||||||
|
// skip the header length (2) and directory entry length (2)
|
||||||
|
file.skipBytes(4);
|
||||||
|
|
||||||
|
// loop through the directories looking for source files
|
||||||
|
int directoryCount = getInt(file.readInt());
|
||||||
|
|
||||||
|
// skip the rest of the header
|
||||||
|
file.skipBytes(8);
|
||||||
|
|
||||||
|
// save the file offset to the base of the directories
|
||||||
|
long directoryOffset = file.getFilePointer();
|
||||||
|
|
||||||
|
for (int i = 0; i < directoryCount; i++) {
|
||||||
|
// seek to the next directory
|
||||||
|
file.seek(directoryOffset + i*12);
|
||||||
|
|
||||||
|
// get the type of the subsection. we only care about source modules
|
||||||
|
short subsectionType = getShort(file.readShort());
|
||||||
|
if (0x127 == subsectionType) {
|
||||||
|
|
||||||
|
// skip the module index
|
||||||
|
file.skipBytes(2);
|
||||||
|
|
||||||
|
// get the offset from the base address
|
||||||
|
int subsectionOffset = getInt(file.readInt());
|
||||||
|
|
||||||
|
// seek to the start of the source module section
|
||||||
|
file.seek(cvData + subsectionOffset);
|
||||||
|
|
||||||
|
// get the number of source files
|
||||||
|
short fileCount = getShort(file.readShort());
|
||||||
|
|
||||||
|
// skip the number of segments
|
||||||
|
file.skipBytes(2);
|
||||||
|
|
||||||
|
// save the file offset to the array of base offsets
|
||||||
|
long arrayOffset = file.getFilePointer();
|
||||||
|
|
||||||
|
// loop through the files and add them to our list
|
||||||
|
for (int j = 0; j < fileCount; j++) {
|
||||||
|
// seek to the correct array entry
|
||||||
|
file.seek(arrayOffset + j*4);
|
||||||
|
|
||||||
|
// get the offset to the first entry and seek to it
|
||||||
|
int offset = getInt(file.readInt());
|
||||||
|
file.seek(cvData + subsectionOffset + offset);
|
||||||
|
|
||||||
|
// get the number of segments
|
||||||
|
short segments = getShort(file.readShort());
|
||||||
|
|
||||||
|
// now skip to the name length
|
||||||
|
file.skipBytes(2 + segments*4 + segments*8);
|
||||||
|
byte nameLength = file.readByte();
|
||||||
|
|
||||||
|
// now extract the filename and add it to our list
|
||||||
|
// if it's not already there
|
||||||
|
byte[] nameBuffer = new byte[nameLength];
|
||||||
|
file.readFully(nameBuffer);
|
||||||
|
String name = new String(nameBuffer);
|
||||||
|
|
||||||
|
if (!fileList.contains(name))
|
||||||
|
fileList.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,12 +16,14 @@ import java.io.RandomAccessFile;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.IAddressFactory;
|
import org.eclipse.cdt.core.IAddressFactory;
|
||||||
|
import org.eclipse.cdt.core.ISymbolReader;
|
||||||
import org.eclipse.cdt.utils.Addr32Factory;
|
import org.eclipse.cdt.utils.Addr32Factory;
|
||||||
import org.eclipse.cdt.utils.coff.Coff.FileHeader;
|
import org.eclipse.cdt.utils.coff.Coff.FileHeader;
|
||||||
import org.eclipse.cdt.utils.coff.Coff.OptionalHeader;
|
import org.eclipse.cdt.utils.coff.Coff.OptionalHeader;
|
||||||
import org.eclipse.cdt.utils.coff.Coff.SectionHeader;
|
import org.eclipse.cdt.utils.coff.Coff.SectionHeader;
|
||||||
import org.eclipse.cdt.utils.coff.Coff.Symbol;
|
import org.eclipse.cdt.utils.coff.Coff.Symbol;
|
||||||
import org.eclipse.cdt.utils.coff.Exe.ExeHeader;
|
import org.eclipse.cdt.utils.coff.Exe.ExeHeader;
|
||||||
|
import org.eclipse.cdt.utils.debug.stabs.StabsReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The PE file header consists of an MS-DOS stub, the PE signalture, the COFF file Header
|
* The PE file header consists of an MS-DOS stub, the PE signalture, the COFF file Header
|
||||||
|
@ -162,9 +164,42 @@ public class PE {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class IMAGE_DEBUG_DIRECTORY {
|
||||||
|
final int DEBUGDIRSZ = 28;
|
||||||
|
public int Characteristics;
|
||||||
|
public int TimeDateStamp;
|
||||||
|
public short MajorVersion;
|
||||||
|
public short MinorVersion;
|
||||||
|
public int Type;
|
||||||
|
public int SizeOfData;
|
||||||
|
public int AddressOfRawData;
|
||||||
|
public int PointerToRawData;
|
||||||
|
|
||||||
|
public IMAGE_DEBUG_DIRECTORY(RandomAccessFile file, long offset) throws IOException {
|
||||||
|
file.seek(offset);
|
||||||
|
byte[] dir = new byte[DEBUGDIRSZ];
|
||||||
|
file.readFully(dir);
|
||||||
|
ReadMemoryAccess memory = new ReadMemoryAccess(dir, true);
|
||||||
|
Characteristics = memory.getInt();
|
||||||
|
TimeDateStamp = memory.getInt();
|
||||||
|
MajorVersion = memory.getShort();
|
||||||
|
MinorVersion = memory.getShort();
|
||||||
|
Type = memory.getInt();
|
||||||
|
SizeOfData = memory.getInt();
|
||||||
|
AddressOfRawData = memory.getInt();
|
||||||
|
PointerToRawData = memory.getInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IMAGE_DATA_DIRECTORY {
|
||||||
|
|
||||||
|
public int VirtualAddress;
|
||||||
|
public int Size;
|
||||||
|
}
|
||||||
|
|
||||||
public static class NTOptionalHeader {
|
public static class NTOptionalHeader {
|
||||||
|
|
||||||
public final static int NTHDRSZ = 68;
|
public final static int NTHDRSZ = 196;
|
||||||
public int ImageBase; // 4 bytes.
|
public int ImageBase; // 4 bytes.
|
||||||
public int SectionAlignment; // 4 bytes.
|
public int SectionAlignment; // 4 bytes.
|
||||||
public int FileAlignment; // 4 bytes.
|
public int FileAlignment; // 4 bytes.
|
||||||
|
@ -186,6 +221,7 @@ public class PE {
|
||||||
public int SizeOfHeapCommit; // 4 bytes.
|
public int SizeOfHeapCommit; // 4 bytes.
|
||||||
public int LoaderFlags; // 4 bytes.
|
public int LoaderFlags; // 4 bytes.
|
||||||
public int NumberOfRvaAndSizes; // 4 bytes.
|
public int NumberOfRvaAndSizes; // 4 bytes.
|
||||||
|
public IMAGE_DATA_DIRECTORY DataDirectory[];
|
||||||
|
|
||||||
public NTOptionalHeader(RandomAccessFile file) throws IOException {
|
public NTOptionalHeader(RandomAccessFile file) throws IOException {
|
||||||
this(file, file.getFilePointer());
|
this(file, file.getFilePointer());
|
||||||
|
@ -217,6 +253,13 @@ public class PE {
|
||||||
SizeOfHeapCommit = memory.getInt();
|
SizeOfHeapCommit = memory.getInt();
|
||||||
LoaderFlags = memory.getInt();
|
LoaderFlags = memory.getInt();
|
||||||
NumberOfRvaAndSizes = memory.getInt();
|
NumberOfRvaAndSizes = memory.getInt();
|
||||||
|
|
||||||
|
DataDirectory = new IMAGE_DATA_DIRECTORY[NumberOfRvaAndSizes]; // 8*16=128 bytes
|
||||||
|
for (int i = 0; i < NumberOfRvaAndSizes; i++) {
|
||||||
|
DataDirectory[i] = new IMAGE_DATA_DIRECTORY();
|
||||||
|
DataDirectory[i].VirtualAddress = memory.getInt();
|
||||||
|
DataDirectory[i].Size = memory.getInt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
@ -353,6 +396,7 @@ public class PE {
|
||||||
switch (magic) {
|
switch (magic) {
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_ALPHA:
|
case PEConstants.IMAGE_FILE_MACHINE_ALPHA:
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_ARM:
|
case PEConstants.IMAGE_FILE_MACHINE_ARM:
|
||||||
|
case PEConstants.IMAGE_FILE_MACHINE_ARM2:
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_ALPHA64:
|
case PEConstants.IMAGE_FILE_MACHINE_ALPHA64:
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_I386:
|
case PEConstants.IMAGE_FILE_MACHINE_I386:
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_IA64:
|
case PEConstants.IMAGE_FILE_MACHINE_IA64:
|
||||||
|
@ -385,6 +429,7 @@ public class PE {
|
||||||
attrib.cpu = "alpha"; //$NON-NLS-1$
|
attrib.cpu = "alpha"; //$NON-NLS-1$
|
||||||
break;
|
break;
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_ARM:
|
case PEConstants.IMAGE_FILE_MACHINE_ARM:
|
||||||
|
case PEConstants.IMAGE_FILE_MACHINE_ARM2:
|
||||||
attrib.cpu = "arm"; //$NON-NLS-1$
|
attrib.cpu = "arm"; //$NON-NLS-1$
|
||||||
break;
|
break;
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_ALPHA64:
|
case PEConstants.IMAGE_FILE_MACHINE_ALPHA64:
|
||||||
|
@ -600,11 +645,12 @@ public class PE {
|
||||||
// FIXME: What is this again ?
|
// FIXME: What is this again ?
|
||||||
if (ntHeader != null)
|
if (ntHeader != null)
|
||||||
symbolTable[i].n_value += ntHeader.ImageBase + ntHeader.FileAlignment;
|
symbolTable[i].n_value += ntHeader.ImageBase + ntHeader.FileAlignment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return symbolTable;
|
return symbolTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public byte[] getStringTable() throws IOException {
|
public byte[] getStringTable() throws IOException {
|
||||||
if (stringTable == null) {
|
if (stringTable == null) {
|
||||||
if (fileHeader.f_nsyms > 0) {
|
if (fileHeader.f_nsyms > 0) {
|
||||||
|
@ -691,12 +737,102 @@ public class PE {
|
||||||
}
|
}
|
||||||
return rfile;
|
return rfile;
|
||||||
}
|
}
|
||||||
public static void main(String[] args) {
|
|
||||||
|
private ISymbolReader createCodeViewReader() {
|
||||||
|
ISymbolReader symReader = null;
|
||||||
|
final int IMAGE_DIRECTORY_ENTRY_DEBUG = 6;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PE pe = new PE(args[0]);
|
// the debug directory is the 6th entry
|
||||||
System.out.println(pe);
|
NTOptionalHeader ntHeader = getNTOptionalHeader();
|
||||||
|
if (ntHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_DEBUG)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int debugDir = ntHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
||||||
|
if (debugDir == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int debugFormats = ntHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size / 28;
|
||||||
|
if (debugFormats == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
SectionHeader[] sections = getSectionHeaders();
|
||||||
|
|
||||||
|
// loop through the section headers to find the .rdata section
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
String name = new String(sections[i].s_name).trim();
|
||||||
|
if (name.equals(".rdata")) {
|
||||||
|
// figure out the file offset of the debug ddirectory entries
|
||||||
|
int offsetInto_rdata = debugDir - sections[i].s_vaddr;
|
||||||
|
int fileOffset = sections[i].s_scnptr + offsetInto_rdata;
|
||||||
|
RandomAccessFile accessFile = getRandomAccessFile();
|
||||||
|
|
||||||
|
// loop through the debug directories looking for CodeView (type 2)
|
||||||
|
for (int j = 0; j < debugFormats; j++) {
|
||||||
|
PE.IMAGE_DEBUG_DIRECTORY dir = new PE.IMAGE_DEBUG_DIRECTORY(
|
||||||
|
accessFile, fileOffset);
|
||||||
|
|
||||||
|
if ((2 == dir.Type) && (dir.SizeOfData > 0)) {
|
||||||
|
// CodeView found, seek to actual data
|
||||||
|
int debugBase = dir.PointerToRawData;
|
||||||
|
accessFile.seek(debugBase);
|
||||||
|
|
||||||
|
// sanity check. the first four bytes of the CodeView
|
||||||
|
// data should be "NB11"
|
||||||
|
String s2 = accessFile.readLine();
|
||||||
|
if (s2.startsWith("NB11")) {
|
||||||
|
Attribute att = getAttribute();
|
||||||
|
symReader = new CodeViewReader(accessFile,
|
||||||
|
debugBase, att.isLittleEndian());
|
||||||
|
return symReader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileOffset += dir.DEBUGDIRSZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return symReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISymbolReader createStabsReader() {
|
||||||
|
ISymbolReader symReader = null;
|
||||||
|
try {
|
||||||
|
SectionHeader[] sections = getSectionHeaders();
|
||||||
|
byte[] stab = null;
|
||||||
|
byte[] stabstr = null;
|
||||||
|
|
||||||
|
// loop through the section headers looking for stabs info
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
String name = new String(sections[i].s_name).trim();
|
||||||
|
if (name.equals(".stab")) {
|
||||||
|
stab = sections[i].getRawData();
|
||||||
|
}
|
||||||
|
if (name.equals(".stabstr")) {
|
||||||
|
stabstr = sections[i].getRawData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we found both sections then proceed
|
||||||
|
if (stab != null && stabstr != null) {
|
||||||
|
Attribute att = getAttribute();
|
||||||
|
symReader = new StabsReader(stab, stabstr, att.isLittleEndian());
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
return symReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISymbolReader getSymbolReader() {
|
||||||
|
ISymbolReader reader = null;
|
||||||
|
reader = createStabsReader();
|
||||||
|
if (reader == null) {
|
||||||
|
reader = createCodeViewReader();
|
||||||
|
}
|
||||||
|
return reader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,9 @@ public final static int IMAGE_FILE_MACHINE_SH3 = 0x1a2;
|
||||||
public final static int IMAGE_FILE_MACHINE_SH4 = 0x1a6;
|
public final static int IMAGE_FILE_MACHINE_SH4 = 0x1a6;
|
||||||
public final static int IMAGE_FILE_MACHINE_THUMB = 0x1c2;
|
public final static int IMAGE_FILE_MACHINE_THUMB = 0x1c2;
|
||||||
|
|
||||||
|
// This is not listed in the PE docs but is generated by some GCC tools.
|
||||||
|
public final static int IMAGE_FILE_MACHINE_ARM2 = 0xa00;
|
||||||
|
|
||||||
/* OptionalHeader.magic */
|
/* OptionalHeader.magic */
|
||||||
public final static int PE32 = 0x10b;
|
public final static int PE32 = 0x10b;
|
||||||
public final static int PE32PLUS = 0x20b;
|
public final static int PE32PLUS = 0x20b;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.IAddressFactory;
|
import org.eclipse.cdt.core.IAddressFactory;
|
||||||
import org.eclipse.cdt.core.IBinaryParser;
|
import org.eclipse.cdt.core.IBinaryParser;
|
||||||
|
import org.eclipse.cdt.core.ISymbolReader;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
||||||
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
|
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
|
||||||
import org.eclipse.cdt.utils.AR;
|
import org.eclipse.cdt.utils.AR;
|
||||||
|
@ -97,6 +98,25 @@ public class PEBinaryObject extends BinaryObjectAdapter {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getAdapter(Class adapter) {
|
||||||
|
if (adapter.equals(PE.class)) {
|
||||||
|
try {
|
||||||
|
if (header != null) {
|
||||||
|
return new PE(getPath().toOSString(), header.getObjectDataOffset());
|
||||||
|
}
|
||||||
|
return new PE(getPath().toOSString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (adapter.equals(ISymbolReader.class)) {
|
||||||
|
PE pe = (PE)getAdapter(PE.class);
|
||||||
|
if (pe != null) {
|
||||||
|
return pe.getSymbolReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.getAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
protected PE getPE() throws IOException {
|
protected PE getPE() throws IOException {
|
||||||
if (header != null) {
|
if (header != null) {
|
||||||
return new PE(getPath().toOSString(), header.getObjectDataOffset());
|
return new PE(getPath().toOSString(), header.getObjectDataOffset());
|
||||||
|
|
|
@ -116,6 +116,7 @@ public class PEParser extends AbstractCExtension implements IBinaryParser {
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_SH3:
|
case PEConstants.IMAGE_FILE_MACHINE_SH3:
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_SH4:
|
case PEConstants.IMAGE_FILE_MACHINE_SH4:
|
||||||
case PEConstants.IMAGE_FILE_MACHINE_THUMB:
|
case PEConstants.IMAGE_FILE_MACHINE_THUMB:
|
||||||
|
case PEConstants.IMAGE_FILE_MACHINE_ARM2:
|
||||||
// Ok;
|
// Ok;
|
||||||
isBin = true;
|
isBin = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -36,6 +36,9 @@ import org.eclipse.cdt.utils.debug.IDebugEntryRequestor;
|
||||||
import org.eclipse.cdt.utils.debug.tools.DebugSym;
|
import org.eclipse.cdt.utils.debug.tools.DebugSym;
|
||||||
import org.eclipse.cdt.utils.debug.tools.DebugSymsRequestor;
|
import org.eclipse.cdt.utils.debug.tools.DebugSymsRequestor;
|
||||||
import org.eclipse.cdt.utils.elf.Elf;
|
import org.eclipse.cdt.utils.elf.Elf;
|
||||||
|
import org.eclipse.cdt.utils.coff.PE;
|
||||||
|
import org.eclipse.cdt.utils.coff.Coff.SectionHeader;
|
||||||
|
import org.eclipse.cdt.utils.coff.PE.Attribute;
|
||||||
|
|
||||||
public class Stabs {
|
public class Stabs {
|
||||||
|
|
||||||
|
@ -58,9 +61,18 @@ public class Stabs {
|
||||||
DebugType voidType = new DebugBaseType("void", 0, false); //$NON-NLS-1$
|
DebugType voidType = new DebugBaseType("void", 0, false); //$NON-NLS-1$
|
||||||
|
|
||||||
public Stabs(String file) throws IOException {
|
public Stabs(String file) throws IOException {
|
||||||
Elf exe = new Elf(file);
|
|
||||||
init(exe);
|
// we support Elf and PE executable formats. try Elf
|
||||||
exe.dispose();
|
// and then PE.
|
||||||
|
try {
|
||||||
|
Elf exe = new Elf(file);
|
||||||
|
init(exe);
|
||||||
|
exe.dispose();
|
||||||
|
} catch (IOException e) {
|
||||||
|
PE exe = new PE(file);
|
||||||
|
init(exe);
|
||||||
|
exe.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stabs(Elf exe) throws IOException {
|
public Stabs(Elf exe) throws IOException {
|
||||||
|
@ -90,6 +102,26 @@ public class Stabs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init(PE exe) throws IOException {
|
||||||
|
byte[] data = null;
|
||||||
|
byte[] stabstr = null;
|
||||||
|
|
||||||
|
SectionHeader[] sections = exe.getSectionHeaders();
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
String name = new String(sections[i].s_name).trim();
|
||||||
|
if (name.equals(".stab")) { //$NON-NLS-1$
|
||||||
|
data = sections[i].getRawData();
|
||||||
|
} else if (name.equals(".stabstr")) { //$NON-NLS-1$
|
||||||
|
stabstr = sections[i].getRawData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribute att = exe.getAttribute();
|
||||||
|
if (data != null && stabstr != null) {
|
||||||
|
init(data, stabstr, att.isLittleEndian());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void init(byte[] stab, byte[] stabstr, boolean le) {
|
void init(byte[] stab, byte[] stabstr, boolean le) {
|
||||||
stabData = stab;
|
stabData = stab;
|
||||||
stabstrData = stabstr;
|
stabstrData = stabstr;
|
||||||
|
@ -453,10 +485,11 @@ public class Stabs {
|
||||||
case 'T' :
|
case 'T' :
|
||||||
{
|
{
|
||||||
String infoField = sf.getTypeInformation();
|
String infoField = sf.getTypeInformation();
|
||||||
// According to the doc 't' can follow the 'T'
|
// According to the doc 't' can follow the 'T'. If so just
|
||||||
|
// strip the T and go again.
|
||||||
if (infoField.length() > 0 && infoField.charAt(0) == 't') {
|
if (infoField.length() > 0 && infoField.charAt(0) == 't') {
|
||||||
//String s = infoField.substring(1);
|
String s = field.replaceFirst(":T", ":");
|
||||||
parseStabString(requestor, field, value);
|
parseStabString(requestor, s, value);
|
||||||
} else {
|
} else {
|
||||||
// Just register the type.
|
// Just register the type.
|
||||||
String name = sf.getName();
|
String name = sf.getName();
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2006 Nokia and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Nokia - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.utils.debug.stabs;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.ISymbolReader;
|
||||||
|
|
||||||
|
public class StabsReader implements ISymbolReader {
|
||||||
|
|
||||||
|
byte[] stabData;
|
||||||
|
byte[] stabstrData;
|
||||||
|
boolean isLe;
|
||||||
|
List fileList;
|
||||||
|
String[] files = null;
|
||||||
|
boolean parsed = false;
|
||||||
|
String currentFile;
|
||||||
|
|
||||||
|
public StabsReader(byte[] data, byte[] stabstr, boolean littleEndian) {
|
||||||
|
stabData = data;
|
||||||
|
stabstrData = stabstr;
|
||||||
|
isLe = littleEndian;
|
||||||
|
|
||||||
|
fileList = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getSourceFiles() {
|
||||||
|
if (!parsed) {
|
||||||
|
parse();
|
||||||
|
|
||||||
|
parsed = true;
|
||||||
|
|
||||||
|
files = new String[fileList.size()];
|
||||||
|
for (int i = 0; i < fileList.size(); i++) {
|
||||||
|
files[i] = (String)fileList.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeString(long offset) {
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
for (; offset < stabstrData.length; offset++) {
|
||||||
|
byte b = stabstrData[(int) offset];
|
||||||
|
if (b == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.append((char) b);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int read_4_bytes(byte[] bytes, int offset) {
|
||||||
|
if (isLe) {
|
||||||
|
return (((bytes[offset + 3] & 0xff) << 24)
|
||||||
|
| ((bytes[offset + 2] & 0xff) << 16)
|
||||||
|
| ((bytes[offset + 1] & 0xff) << 8)
|
||||||
|
| (bytes[offset] & 0xff));
|
||||||
|
}
|
||||||
|
return (((bytes[offset] & 0xff) << 24)
|
||||||
|
| ((bytes[offset + 1] & 0xff) << 16)
|
||||||
|
| ((bytes[offset + 2] & 0xff) << 8)
|
||||||
|
| (bytes[offset + 3] & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
private short read_2_bytes(byte[] bytes, int offset) {
|
||||||
|
if (isLe) {
|
||||||
|
return (short) (((bytes[offset + 1] & 0xff) << 8) | (bytes[offset] & 0xff));
|
||||||
|
}
|
||||||
|
return (short) (((bytes[offset] & 0xff) << 8) | (bytes[offset + 1] & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String fixUpPath(String path) {
|
||||||
|
// some compilers generate extra back slashes
|
||||||
|
path = path.replaceAll("\\\\\\\\", "\\\\");
|
||||||
|
|
||||||
|
// translate any cygwin drive paths, e.g. //G/System/main.cpp or /cygdrive/c/system/main.c
|
||||||
|
if (path.startsWith("/cygdrive/") && ('/' == path.charAt(11))) {
|
||||||
|
char driveLetter = path.charAt(10);
|
||||||
|
driveLetter = (Character.isLowerCase(driveLetter)) ? Character.toUpperCase(driveLetter) : driveLetter;
|
||||||
|
|
||||||
|
StringBuffer buf = new StringBuffer(path);
|
||||||
|
buf.delete(0, 11);
|
||||||
|
buf.insert(0, driveLetter);
|
||||||
|
buf.insert(1, ':');
|
||||||
|
|
||||||
|
path = buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate any cygwin drive paths, e.g. //G/System/main.cpp or /cygdrive/c/system/main.c
|
||||||
|
if (path.startsWith("//") && ('/' == path.charAt(3))) {
|
||||||
|
char driveLetter = path.charAt(2);
|
||||||
|
driveLetter = (Character.isLowerCase(driveLetter)) ? Character.toUpperCase(driveLetter) : driveLetter;
|
||||||
|
|
||||||
|
StringBuffer buf = new StringBuffer(path);
|
||||||
|
buf.delete(0, 3);
|
||||||
|
buf.insert(0, driveLetter);
|
||||||
|
buf.insert(1, ':');
|
||||||
|
|
||||||
|
path = buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse() {
|
||||||
|
long nstab = stabData.length / StabConstant.SIZE;
|
||||||
|
int i, offset;
|
||||||
|
String holder = null;
|
||||||
|
long stroff = 0;
|
||||||
|
int type = 0;
|
||||||
|
int other = 0;
|
||||||
|
short desc = 0;
|
||||||
|
long value = 0;
|
||||||
|
|
||||||
|
for (i = offset = 0; i < nstab; i++, offset += StabConstant.SIZE) {
|
||||||
|
|
||||||
|
// get the type; 1 byte;
|
||||||
|
type = 0xff & stabData[offset + 4];
|
||||||
|
|
||||||
|
// ignoring anything other than N_SO and N_SOL because these are source or
|
||||||
|
// object file entries
|
||||||
|
if (type == StabConstant.N_SO || type == StabConstant.N_SOL) {
|
||||||
|
// get the other
|
||||||
|
other = 0xff & stabData[offset + 5];
|
||||||
|
// get the desc
|
||||||
|
desc = read_2_bytes(stabData, offset + 6);
|
||||||
|
// get the value
|
||||||
|
value = read_4_bytes(stabData, offset + 8);
|
||||||
|
|
||||||
|
// get the offset for the string; 4 bytes
|
||||||
|
stroff = read_4_bytes(stabData, offset);
|
||||||
|
|
||||||
|
String field;
|
||||||
|
if (stroff > 0) {
|
||||||
|
field = makeString(stroff);
|
||||||
|
} else {
|
||||||
|
field = new String();
|
||||||
|
}
|
||||||
|
// Check for continuation and if any go to the next stab
|
||||||
|
// until we find a string that is not terminated with a
|
||||||
|
// continuation line '\\'
|
||||||
|
// According to the spec all the other fields are duplicated so we
|
||||||
|
// still have the data.
|
||||||
|
// From the spec continuation line on AIX is '?'
|
||||||
|
if (field.endsWith("\\") || field.endsWith("?")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
field = field.substring(0, field.length() - 1);
|
||||||
|
if (holder == null) {
|
||||||
|
holder = field;
|
||||||
|
} else {
|
||||||
|
holder += field;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (holder != null) {
|
||||||
|
field = holder + field;
|
||||||
|
holder = null;
|
||||||
|
}
|
||||||
|
parseStabEntry(field, type, other, desc, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseStabEntry(String field, int type, int other, short desc, long value) {
|
||||||
|
// Parse the string
|
||||||
|
switch (type) {
|
||||||
|
case StabConstant.N_SOL :
|
||||||
|
// include file
|
||||||
|
if (field != null && field.length() > 0) {
|
||||||
|
|
||||||
|
field = fixUpPath(field);
|
||||||
|
|
||||||
|
if (!fileList.contains(field))
|
||||||
|
fileList.add(field);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StabConstant.N_SO :
|
||||||
|
// source file
|
||||||
|
if (field != null && field.length() > 0) {
|
||||||
|
// if it ends with "/" then the next entry will be the rest of the string.
|
||||||
|
if (field.endsWith("/")) { //$NON-NLS-1$
|
||||||
|
currentFile = field;
|
||||||
|
} else {
|
||||||
|
if (currentFile != null) {
|
||||||
|
// if this entry is an absolute path then just throw away the existing currentFile
|
||||||
|
if (new File(field).isAbsolute()) {
|
||||||
|
currentFile = field;
|
||||||
|
} else {
|
||||||
|
currentFile += field;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentFile = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
currentFile = fixUpPath(currentFile);
|
||||||
|
|
||||||
|
if (!fileList.contains(currentFile))
|
||||||
|
fileList.add(currentFile);
|
||||||
|
|
||||||
|
currentFile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue