1
0
Fork 0
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:
David Inglis 2006-02-25 04:23:53 +00:00
parent 3502da3b30
commit 06a50c17f7
9 changed files with 699 additions and 21 deletions

View file

@ -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;

View file

@ -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();
}

View file

@ -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);
}
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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());

View file

@ -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;

View file

@ -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();

View file

@ -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;
}
}
}