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.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.ISymbolReader;
|
||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryExecutable;
|
||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
|
||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryShared;
|
||||
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
|
||||
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.IBuffer;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
public class Binary extends Openable implements IBinary {
|
||||
|
||||
|
@ -240,16 +245,22 @@ public class Binary extends Openable implements IBinary {
|
|||
Map hash = new HashMap();
|
||||
IBinaryObject obj = getBinaryObject();
|
||||
if (obj != null) {
|
||||
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;
|
||||
// First check if we can get the list of source
|
||||
// files used to build the binary from the symbol
|
||||
// information. if not, fall back on information from the binary parser.
|
||||
if (!addSourceFiles(info, obj, hash))
|
||||
{
|
||||
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 :
|
||||
addVariable(info, symbols[i], hash);
|
||||
break;
|
||||
case ISymbol.VARIABLE :
|
||||
addVariable(info, symbols[i], hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
|
@ -258,6 +269,73 @@ public class Binary extends Openable implements IBinary {
|
|||
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 {
|
||||
IPath filename = filename = symbol.getFilename();
|
||||
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.IAddressFactory;
|
||||
import org.eclipse.cdt.core.ISymbolReader;
|
||||
import org.eclipse.cdt.utils.Addr32Factory;
|
||||
import org.eclipse.cdt.utils.coff.Coff.FileHeader;
|
||||
import org.eclipse.cdt.utils.coff.Coff.OptionalHeader;
|
||||
import org.eclipse.cdt.utils.coff.Coff.SectionHeader;
|
||||
import org.eclipse.cdt.utils.coff.Coff.Symbol;
|
||||
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
|
||||
|
@ -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 final static int NTHDRSZ = 68;
|
||||
public final static int NTHDRSZ = 196;
|
||||
public int ImageBase; // 4 bytes.
|
||||
public int SectionAlignment; // 4 bytes.
|
||||
public int FileAlignment; // 4 bytes.
|
||||
|
@ -186,6 +221,7 @@ public class PE {
|
|||
public int SizeOfHeapCommit; // 4 bytes.
|
||||
public int LoaderFlags; // 4 bytes.
|
||||
public int NumberOfRvaAndSizes; // 4 bytes.
|
||||
public IMAGE_DATA_DIRECTORY DataDirectory[];
|
||||
|
||||
public NTOptionalHeader(RandomAccessFile file) throws IOException {
|
||||
this(file, file.getFilePointer());
|
||||
|
@ -217,6 +253,13 @@ public class PE {
|
|||
SizeOfHeapCommit = memory.getInt();
|
||||
LoaderFlags = 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() {
|
||||
|
@ -353,6 +396,7 @@ public class PE {
|
|||
switch (magic) {
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ALPHA:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ARM:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ARM2:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ALPHA64:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_I386:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_IA64:
|
||||
|
@ -385,6 +429,7 @@ public class PE {
|
|||
attrib.cpu = "alpha"; //$NON-NLS-1$
|
||||
break;
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ARM:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ARM2:
|
||||
attrib.cpu = "arm"; //$NON-NLS-1$
|
||||
break;
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ALPHA64:
|
||||
|
@ -605,6 +650,7 @@ public class PE {
|
|||
return symbolTable;
|
||||
}
|
||||
|
||||
|
||||
public byte[] getStringTable() throws IOException {
|
||||
if (stringTable == null) {
|
||||
if (fileHeader.f_nsyms > 0) {
|
||||
|
@ -691,12 +737,102 @@ public class PE {
|
|||
}
|
||||
return rfile;
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
|
||||
private ISymbolReader createCodeViewReader() {
|
||||
ISymbolReader symReader = null;
|
||||
final int IMAGE_DIRECTORY_ENTRY_DEBUG = 6;
|
||||
|
||||
try {
|
||||
PE pe = new PE(args[0]);
|
||||
System.out.println(pe);
|
||||
// the debug directory is the 6th entry
|
||||
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) {
|
||||
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_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 */
|
||||
public final static int PE32 = 0x10b;
|
||||
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.IBinaryParser;
|
||||
import org.eclipse.cdt.core.ISymbolReader;
|
||||
import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
|
||||
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
|
||||
import org.eclipse.cdt.utils.AR;
|
||||
|
@ -97,6 +98,25 @@ public class PEBinaryObject extends BinaryObjectAdapter {
|
|||
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 {
|
||||
if (header != null) {
|
||||
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_SH4:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_THUMB:
|
||||
case PEConstants.IMAGE_FILE_MACHINE_ARM2:
|
||||
// Ok;
|
||||
isBin = true;
|
||||
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.DebugSymsRequestor;
|
||||
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 {
|
||||
|
||||
|
@ -58,9 +61,18 @@ public class Stabs {
|
|||
DebugType voidType = new DebugBaseType("void", 0, false); //$NON-NLS-1$
|
||||
|
||||
public Stabs(String file) throws IOException {
|
||||
Elf exe = new Elf(file);
|
||||
init(exe);
|
||||
exe.dispose();
|
||||
|
||||
// we support Elf and PE executable formats. try Elf
|
||||
// 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 {
|
||||
|
@ -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) {
|
||||
stabData = stab;
|
||||
stabstrData = stabstr;
|
||||
|
@ -453,10 +485,11 @@ public class Stabs {
|
|||
case 'T' :
|
||||
{
|
||||
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') {
|
||||
//String s = infoField.substring(1);
|
||||
parseStabString(requestor, field, value);
|
||||
String s = field.replaceFirst(":T", ":");
|
||||
parseStabString(requestor, s, value);
|
||||
} else {
|
||||
// Just register the type.
|
||||
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