/*******************************************************************************
* Copyright (c) 2000, 2008 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.utils.debug.stabs;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.utils.coff.PE;
import org.eclipse.cdt.utils.coff.Coff.SectionHeader;
import org.eclipse.cdt.utils.coff.PE.Attribute;
import org.eclipse.cdt.utils.debug.DebugArrayType;
import org.eclipse.cdt.utils.debug.DebugBaseType;
import org.eclipse.cdt.utils.debug.DebugCrossRefType;
import org.eclipse.cdt.utils.debug.DebugEnumField;
import org.eclipse.cdt.utils.debug.DebugEnumType;
import org.eclipse.cdt.utils.debug.DebugField;
import org.eclipse.cdt.utils.debug.DebugFunctionType;
import org.eclipse.cdt.utils.debug.DebugParameterKind;
import org.eclipse.cdt.utils.debug.DebugPointerType;
import org.eclipse.cdt.utils.debug.DebugReferenceType;
import org.eclipse.cdt.utils.debug.DebugStructType;
import org.eclipse.cdt.utils.debug.DebugType;
import org.eclipse.cdt.utils.debug.DebugUnknownType;
import org.eclipse.cdt.utils.debug.DebugVariableKind;
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.elf.Elf.Section;
public class Stabs {
final static String LLLOW = "01000000000000000000000"; //$NON-NLS-1$
final static String LLHIGH = "0777777777777777777777"; //$NON-NLS-1$
final static String ULLHIGH = "01777777777777777777777"; //$NON-NLS-1$
byte[] stabData;
byte[] stabstrData;
boolean isLe;
boolean inCompilationUnit;
boolean inFunction;
boolean inInclude;
int bracket;
String currentFile;
Map<TypeNumber, DebugType> mapTypes = new HashMap<TypeNumber, DebugType>();
DebugType voidType = new DebugBaseType("void", 0, false); //$NON-NLS-1$
public Stabs(String file) throws IOException {
// 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 {
init(exe);
}
public Stabs(byte[] stab, byte[] stabstr, boolean le) {
init(stab, stabstr, le);
}
void init(Elf exe) throws IOException {
byte[] data = null;
byte[] stabstr = null;
Elf.Section[] sections = exe.getSections();
for (Section section : sections) {
String name = section.toString();
if (name.equals(".stab")) { //$NON-NLS-1$
data = section.loadSectionData();
} else if (name.equals(".stabstr")) { //$NON-NLS-1$
stabstr = section.loadSectionData();
}
}
Elf.ELFhdr header = exe.getELFhdr();
boolean isLE = header.e_ident[Elf.ELFhdr.EI_DATA] == Elf.ELFhdr.ELFDATA2LSB;
if (data != null && stabstr != null) {
init(data, stabstr, isLE);
}
}
void init(PE exe) throws IOException {
byte[] data = null;
byte[] stabstr = null;
SectionHeader[] sections = exe.getSectionHeaders();
for (SectionHeader section : sections) {
String name = new String(section.s_name).trim();
if (name.equals(".stab")) { //$NON-NLS-1$
data = section.getRawData();
} else if (name.equals(".stabstr")) { //$NON-NLS-1$
stabstr = section.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;
isLe = le;
}
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();
}
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));
}
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));
}
public void parse(IDebugEntryRequestor requestor) {
//List list = new ArrayList();
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 (bracket = i = offset = 0; i < nstab; i++, offset += StabConstant.SIZE) {
// get the offset for the string; 4 bytes
stroff = read_4_bytes(stabData, offset);
// get the type; 1 byte;
type = 0xff & stabData[offset + 4];
// 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);
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(requestor, field, type, other, desc, value);
}
// Bring closure.
if (inFunction) {
requestor.exitFunction(-1);
inFunction = false;
}
if (inInclude) {
requestor.exitInclude();
inInclude = false;
}
if (inCompilationUnit) {
requestor.exitCompilationUnit(value);
inCompilationUnit = false;
currentFile = null;
}
}
void parseStabEntry(IDebugEntryRequestor requestor, String field, int type, int other, short desc, long value) {
// Parse the string
switch (type) {
case StabConstant.N_GSYM :
case StabConstant.N_LSYM :
case StabConstant.N_PSYM :
//accept a new variable
parseStabString(requestor, field, value);
break;
case StabConstant.N_SLINE :
// New statement line
requestor.acceptStatement(desc, value);
break;
case StabConstant.N_FUN :
if (inFunction) {
requestor.exitFunction(value);
inFunction = false;
}
// Start a new Function
if (field.length() == 0) {
field = " anon "; //$NON-NLS-1$
}
inFunction = true;
parseStabString(requestor, field, value);
break;
case StabConstant.N_LBRAC :
if (inFunction) {
requestor.enterCodeBlock(value);
}
bracket++;
break;
case StabConstant.N_RBRAC :
requestor.exitCodeBlock(value);
bracket--;
break;
case StabConstant.N_BINCL :
// Start of an include file
requestor.enterInclude(field);
inInclude = true;
break;
case StabConstant.N_EINCL :
// end of the include
requestor.exitInclude();
inInclude = false;
break;
case StabConstant.N_SOL :
// if we had an include it means the end.
if (inInclude) {
requestor.exitInclude();
inInclude = false;
}
// Start of an include file
requestor.enterInclude(field);
inInclude = true;
break;
case StabConstant.N_CATCH :
parseStabString(requestor, field, value);
break;
case StabConstant.N_SO :
// if whitin a function
if (inFunction) {
requestor.exitFunction(-1);
inFunction = false;
}
if (inInclude) {
requestor.exitInclude();
inInclude = false;
}
if (inCompilationUnit) {
requestor.exitCompilationUnit(value);
inCompilationUnit = false;
currentFile = null;
}
if (field != null && field.length() > 0) {
// if it ends with "/" do not call the entering yet
// we have to concatenate the next one.
if (field.endsWith("/")) { //$NON-NLS-1$
currentFile = field;
} else {
if (currentFile != null) {
currentFile += field;
} else {
currentFile = field;
}
requestor.enterCompilationUnit(currentFile, value);
inCompilationUnit = true;
currentFile = null;
}
}
break;
}
//System.out.println(" " + i + "\t" + Stab.type2String(type) + "\t" +
// other + "\t\t" +
// desc + "\t" + Long.toHexString(value) + "\t" + + stroff + "\t\t"
// +name);
}
void parseStabString(IDebugEntryRequestor requestor, String field, long value) {
StringField sf = new StringField(field);
switch (sf.getSymbolDescriptor()) {
// C++ nested symbol.
case ':' :
break;
// Parameter pass by reference in register.
case 'a' :
{
String information = sf.getTypeInformation();
String paramName = sf.getName();
DebugParameterKind paramKind = DebugParameterKind.REGISTER_REFERENCE;
DebugType paramType = parseStabType("", information); //$NON-NLS-1$
requestor.acceptParameter(paramName, paramType, paramKind, value);
}
break;
// Sun Based variable
case 'b' :
break;
// symbol descriptor indicates that this stab represents a
// constant.
case 'c' :
{
String name = sf.getName();
String information = sf.getTypeInformation();
parseStabConstant(requestor, name, information, value);
}
break;
// Conformant array bound(Pascal).
// Nave of a caught exception GNU C++
case 'C' :
{
String excName = sf.getName();
String information = sf.getTypeInformation();
DebugType excType = parseStabType("", information); //$NON-NLS-1$
requestor.acceptCaughtException(excName, excType, value);
}
break;
// File scope function.
case 'f' :
// Global function.
case 'F' :
{
String funcName = sf.getName();
String funcInfo = sf.getTypeInformation();
DebugType funcType = parseStabType("", funcInfo); //$NON-NLS-1$
boolean funcGlobal = sf.getSymbolDescriptor() == 'F';
requestor.enterFunction(funcName, funcType, funcGlobal, value);
}
break;
// Global variable
case 'G' :
{
String varName = sf.getName();
String varInfo = sf.getTypeInformation();
DebugVariableKind varKind = DebugVariableKind.GLOBAL;
DebugType varType = parseStabType("", varInfo); //$NON-NLS-1$
requestor.acceptVariable(varName, varType, varKind, value);
}
break;
// ???
case 'i' :
break;
// Internal(nested) procedure.
case 'I' :
break;
// Internal/nested function.
case 'J' :
break;
// Label name
case 'L' :
break;
// Module
case 'm' :
break;
// Argument list parameter
case 'p' :
{
String paramName = sf.getName();
String paramInfo = sf.getTypeInformation();
DebugParameterKind paramKind = DebugParameterKind.STACK;
DebugType paramType = parseStabType("", paramInfo); //$NON-NLS-1$
requestor.acceptParameter(paramName, paramType, paramKind, value);
}
break;
// Paramater in floating point register.
case 'D' :
// register parameter or prototype f function referenced by the
// file.
case 'P' :
// Register Parameter
case 'R' :
{
String paramName = sf.getName();
String paramInfo = sf.getTypeInformation();
DebugParameterKind paramKind = DebugParameterKind.REGISTER;
DebugType paramType = parseStabType("", paramInfo); //$NON-NLS-1$
requestor.acceptParameter(paramName, paramType, paramKind, value);
}
break;
// static procedure
case 'Q' :
break;
// Floating point register variable
case 'd' :
// Never use, according to the
// Register variable
case 'r' :
{
String varName = sf.getName();
String varInfo = sf.getTypeInformation();
DebugVariableKind varKind = DebugVariableKind.REGISTER;
DebugType varType = parseStabType("", varInfo); //$NON-NLS-1$
requestor.acceptVariable(varName, varType, varKind, value);
}
break;
// File scope variable
case 'S' :
{
String varName = sf.getName();
String varInfo = sf.getTypeInformation();
DebugVariableKind varKind = DebugVariableKind.STATIC;
DebugType varType = parseStabType("", varInfo); //$NON-NLS-1$
requestor.acceptVariable(varName, varType, varKind, value);
}
break;
// Type name
case 't' :
{
String name = sf.getName();
String infoField = sf.getTypeInformation();
DebugType type = parseStabType(name, infoField);
requestor.acceptTypeDef(name, type);
}
break;
// Enumeration, structure or union
case 'T' :
{
String infoField = sf.getTypeInformation();
// 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 = field.replaceFirst(":T", ":"); //$NON-NLS-1$ //$NON-NLS-2$
parseStabString(requestor, s, value);
} else {
// Just register the type.
String name = sf.getName();
parseStabType(name, infoField);
}
}
break;
// Parameter passed by reference.
case 'v' :
{
String paramName = sf.getName();
String paramInfo = sf.getTypeInformation();
DebugParameterKind paramKind = DebugParameterKind.REFERENCE;
DebugType paramType = parseStabType("", paramInfo); //$NON-NLS-1$
requestor.acceptParameter(paramName, paramType, paramKind, value);
}
break;
// Procedure scope static variable
case 'V' :
{
String varName = sf.getName();
String varInfo = sf.getTypeInformation();
DebugVariableKind varKind = DebugVariableKind.LOCAL_STATIC;
DebugType varType = parseStabType("", varInfo); //$NON-NLS-1$
requestor.acceptVariable(varName, varType, varKind, value);
}
break;
// Conformant array
case 'x' :
break;
// Function return variable
case 'X' :
// local variable
case 's' :
// Variable on the stack
case '-' :
default :
{
String varName = sf.getName();
String varInfo = sf.getTypeInformation();
DebugVariableKind varKind = DebugVariableKind.LOCAL;
DebugType varType = parseStabType("", varInfo); //$NON-NLS-1$
requestor.acceptVariable(varName, varType, varKind, value);
}
break;
}
}
DebugType parseStabType(String name, String typeInformation) {
try {
Reader reader = new StringReader(typeInformation);
return parseStabType(name, reader);
} catch (IOException e) {
}
return new DebugUnknownType(name);
}
DebugType parseStabType(String name, Reader reader) throws IOException {
return parseStabType(name, null, reader);
}
DebugType parseStabType(String name, TypeInformation oldType, Reader reader) throws IOException {
TypeInformation typeInfo = new TypeInformation(reader);
DebugType type = null;
switch (typeInfo.getTypeDescriptor()) {
// Method (C++)
case '#' :
break;
// Reference (C++)
case '&' :
{
DebugType subType = parseStabType("", reader); //$NON-NLS-1$
type = new DebugReferenceType(subType);
}
break;
// Member (C++) class and variable
case '@' :
break;
// pointer type.
case '*' :
{
DebugType subType = parseStabType("", reader); //$NON-NLS-1$
type = new DebugPointerType(subType);
}
break;
// Builtin type define byt Sun stabs
// Pascal Type
case 'b' :
// Builtin floating type
case 'R' :
// Wide character
case 'w' :
// Builtin flaoting point type.
case 'g' :
// Complex buitin type.
case 'c' :
{
char desc = typeInfo.getTypeDescriptor();
type = parseStabBuiltinType(name, desc, reader);
}
break;
// Array.
case 'a' :
case 'A' :
type = parseStabArrayType(name, reader);
break;
// Volatile-qualified type
case 'B' :
break;
// Cobol
case 'C' :
break;
// File type
case 'd' :
break;
// N-dimensional dynamic array.
case 'D' :
break;
// Enumeration type
case 'e' :
type = parseStabEnumType(name, reader);
break;
// N-dimensional subarray
case 'E' :
break;
// Function type
case 'f' :
{
DebugType subType = parseStabType("", reader); //$NON-NLS-1$
type = new DebugFunctionType(subType);
}
break;
// Pascal Function parameter
case 'F' :
break;
// COBOL Group
case 'G' :
break;
// Imported type
case 'i' :
break;
// Const-qualified type
case 'k' :
break;
// Cobol file desc.
case 'K' :
break;
// Multiple instance type
case 'M' :
break;
// string type:
case 'n' :
break;
// Stringpt:
case 'N' :
break;
// Opaque type
case 'o' :
break;
// Procedure
case 'p' :
break;
// Packed array
case 'P' :
break;
// Range. example:
case 'r' :
type = parseStabRangeType(name, typeInfo.getTypeNumber(), reader);
break;
// Structure type
case 's' :
type = parseStabStructType(name, typeInfo.getTypeNumber(), false, reader);
break;
// Union
case 'u' :
type = parseStabStructType(name, typeInfo.getTypeNumber(), true, reader);
break;
// Set type
case 'S' :
break;
// variant record.
case 'v' :
break;
// Cross-reference
case 'x' :
type = parseStabCrossRefType(name, reader);
break;
// ???
case 'Y' :
break;
// gstring
case 'z' :
break;
// Reference to a previously define type.
case '(' :
case '-' :
default :
if (typeInfo.isTypeDefinition()) {
type = parseStabType(name, typeInfo, reader);
} else {
// check for void
if (oldType != null && oldType.getTypeNumber().equals(typeInfo.getTypeNumber())) {
type = voidType;
} else {
type = getDebugType(typeInfo.getTypeNumber());
}
}
}
// register the type.
if (type != null && typeInfo.isTypeDefinition()) {
mapTypes.put(typeInfo.getTypeNumber(), type);
}
if (type == null) {
type = new DebugUnknownType(name);
}
return type;
}
/**
* @param name
* @param reader
* @return
*/
DebugType parseStabCrossRefType(String name, Reader reader) throws IOException {
StringBuffer sb = new StringBuffer();
int c = reader.read();
if (c == 's') {
sb.append("struct "); //$NON-NLS-1$
} else if (c == 'u') {
sb.append("union "); //$NON-NLS-1$
} else if (c == 'e') {
sb.append("enum "); //$NON-NLS-1$
} else {
sb.append((char) c);
}
while ((c = reader.read()) != -1) {
if (c == ':') {
break;
}
sb.append((char) c);
}
return new DebugCrossRefType(null, name, sb.toString());
}
/**
* @param name
* @param desc
* @param reader
* @return
*/
private DebugType parseStabBuiltinType(String name, char desc, Reader reader) throws IOException {
DebugType builtinType = null;
switch (desc) {
case 'b' :
{
// get the signed
int signed = reader.read();
reader.mark(1);
// get the flag
int charFlag = reader.read();
if (charFlag != 'c') {
reader.reset();
}
int c;
StringBuffer sb = new StringBuffer();
// get the width
//int width = 0;
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
//try {
// String token = sb.toString();
// width = Integer.parseInt(token);
//} catch (NumberFormatException e) {
//}
sb.setLength(0);
// get the offset
//int offset = 0;
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
//try {
//String token = sb.toString();
//offset = Integer.parseInt(token);
//} catch (NumberFormatException e) {
//}
sb.setLength(0);
// get the nbits
int nbits = 0;
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
try {
String token = sb.toString();
nbits = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
builtinType = new DebugBaseType(name, nbits / 8, signed == 'u');
}
break;
case 'w' :
{
builtinType = new DebugBaseType(name, 8, false);
}
break;
case 'R' :
{
int c;
StringBuffer sb = new StringBuffer();
// get the fp-Type
//int fpType = 0;
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
//try {
// String token = sb.toString();
//fpType = Integer.parseInt(token);
//} catch (NumberFormatException e) {
//}
sb.setLength(0);
// get the bytes
int bytes = 0;
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
try {
String token = sb.toString();
bytes = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
builtinType = new DebugBaseType(name, bytes, false);
}
break;
case 'c' :
case 'g' :
{
//DebugType type = parseStabType(name, reader);
parseStabType(name, reader);
int c = reader.read(); // semicolon
StringBuffer sb = new StringBuffer();
int nbits = 0;
while ((c = reader.read()) != -1) {
sb.append((char) c);
}
try {
String token = sb.toString();
nbits = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
builtinType = new DebugBaseType(name, nbits / 8, false);
}
break;
}
return builtinType;
}
DebugType parseStabArrayType(String name, Reader reader) throws IOException {
// Format of an array type:
// "ar<index type>;lower;upper;<array_contents_type>".
// we only understand range for an array.
int c = reader.read();
if (c == 'r') {
//DebugType index_type = parseStabType("", reader); //$NON-NLS-1$
parseStabType("", reader); //$NON-NLS-1$
c = reader.read();
// Check ';'
if (c != ';') {
// bad array type
return null;
}
StringBuffer sb = new StringBuffer();
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
// Check ';'
if (c != ';') {
// bad array type
return null;
}
// lower index
int lower = 0; // should always be zero for C/C++
try {
String token = sb.toString();
lower = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
sb.setLength(0);
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
// Check ';'
if (c != ';') {
// bad array type
return null;
}
int upper = 0;
// upper index
try {
String token = sb.toString();
upper = Integer.parseInt(token);
} catch (NumberFormatException e) {
}
// Check ';'
if (c != ';') {
// bad array type
return null;
}
// The array_content_type
DebugType subType = parseStabType("", reader); //$NON-NLS-1$
return new DebugArrayType(subType, upper - lower + 1);
}
return new DebugArrayType(new DebugUnknownType(name), 0);
}
/**
* _Bool:t(0,20)=eFalse:0,True:1,; fruit:T(1,4)=eapple:0,orange:1,;
*
* @param name
* @param attributes
* @return
*/
DebugType parseStabEnumType(String name, Reader reader) throws IOException {
List<DebugEnumField> list = new ArrayList<DebugEnumField>();
String fieldName = null;
StringBuffer sb = new StringBuffer();
int c;
while ((c = reader.read()) != -1) {
if (c == ':') {
fieldName = sb.toString();
sb.setLength(0);
} else if (c == ',') {
if (fieldName != null && fieldName.length() > 0) {
String value = sb.toString();
int fieldValue = 0;
try {
fieldValue = Integer.decode(value).intValue();
} catch (NumberFormatException e) {
}
list.add(new DebugEnumField(fieldName, fieldValue));
}
fieldName = null;
sb.setLength(0);
} else if (c == ';') {
break;
} else {
sb.append((char) c);
}
}
DebugEnumField[] fields = new DebugEnumField[list.size()];
list.toArray(fields);
return new DebugEnumType(name, fields);
}
/**
* For C lang -- node:T(1,5)=s12i:(0,1),0,32;j:(0,1),32,32;next:(1,6)=*(1,5),64,32;;
*
* @param name
* @param typeNumber
* @param union
* @param reader
* @return
*/
DebugType parseStabStructType(String name, TypeNumber typeNumber, boolean union, Reader reader) throws IOException {
int c;
StringBuffer sb = new StringBuffer();
while ((c = reader.read()) != -1) {
if (!Character.isDigit((char) c)) {
reader.reset();
break;
}
reader.mark(1);
sb.append((char) c);
}
String number = sb.toString();
int size = 0;
try {
size = Integer.decode(number).intValue();
} catch (NumberFormatException e) {
}
DebugStructType structType = new DebugStructType(name, size, union);
// We have to register it right away, some field may
// need the tag if they self reference via a pointer.
mapTypes.put(typeNumber, structType);
// parse the fields.
parseStabStructField(structType, reader);
return structType;
}
void parseStabStructField(DebugStructType structType, Reader reader) throws IOException {
// get the field name.
StringBuffer sb = new StringBuffer();
int c;
while ((c = reader.read()) != -1) {
if (c != ':') {
sb.append((char) c);
} else {
break;
}
}
// Sanity check: We should have ':' if no bailout
if (c != ':') {
return;
}
String name = sb.toString();
// get the type of the field
DebugType fieldType = parseStabType("", reader); //$NON-NLS-1$
c = reader.read();
// Sanity check: we should have ',' here.
if (c != ',') {
return;
}
// the offset of the struct of the field.
sb.setLength(0);
while ((c = reader.read()) != -1 && c != ',') {
sb.append((char) c);
}
// Sanity check: we should have ','
if (c != ',') {
return;
}
int offset = 0;
try {
offset = Integer.decode(sb.toString()).intValue();
} catch (NumberFormatException e) {
}
// the number of bits of the struct of the field.
sb.setLength(0);
while ((c = reader.read()) != -1 && c != ';') {
sb.append((char) c);
}
// Check we need ';'
if (c != ';') {
return;
}
int bits = 0;
try {
bits = Integer.decode(sb.toString()).intValue();
} catch (NumberFormatException e) {
}
// add the new field.
structType.addField(new DebugField(name, fieldType, offset, bits));
// absorb the trailing ';'
//reader.read();
// continue the parsing recursively.
parseStabStructField(structType, reader);
}
DebugType parseStabRangeType(String name, TypeNumber number, Reader reader) throws IOException {
// int:t(0,1)=r(0,1);-2147483648;2147483647;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
DebugType rangeType = null;
// get the index_type
TypeNumber typeNumber = new TypeNumber(reader);
int c = reader.read();
// Sanity we should have a semicolon
if (c != ';') {
// bad range type;
return new DebugUnknownType(name);
}
StringBuffer sb = new StringBuffer();
// read the lowerBound.
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
// Sanity we should have a semicolon
if (c != ';') {
// bad range type;
return new DebugUnknownType(name);
}
boolean overflowLowerBound = false;
String lowerBoundString = sb.toString();
long lowerBound = 0;
try {
lowerBound = Long.decode(lowerBoundString).longValue();
} catch (NumberFormatException e) {
overflowLowerBound = true;
}
sb.setLength(0);
// read the upperBound.
while ((c = reader.read()) != -1) {
if (c == ';') {
break;
}
sb.append((char) c);
}
// Sanity we should have a semicolon
if (c != ';') {
// bad range type;
return new DebugUnknownType(name);
}
boolean overflowUpperBound = false;
long upperBound = 0;
String upperBoundString = sb.toString();
try {
upperBound = Long.decode(upperBoundString).longValue();
} catch (NumberFormatException e) {
overflowUpperBound = true;
}
boolean self = typeNumber.equals(number);
// Probably trying 64 bits range like "long long"
if (overflowLowerBound || overflowUpperBound) {
if (lowerBoundString.equals(LLLOW) && upperBoundString.equals(LLHIGH))
rangeType = new DebugBaseType(name, 8, false);
if (!overflowLowerBound && lowerBound == 0 && upperBoundString.equals(ULLHIGH))
rangeType = new DebugBaseType(name, 8, true);
} else {
if (lowerBound == 0 && upperBound == -1) {
// if the lower bound is 0 and the upper bound is -1,
// it means unsigned int
if (name.equals("long long int")) { //$NON-NLS-1$
rangeType = new DebugBaseType(name, 8, true);
} else if (name.equals("long long unsigned int")) { //$NON-NLS-1$
rangeType = new DebugBaseType(name, 8, true);
} else {
rangeType = new DebugBaseType(name, 4, true);
}
} else if (upperBound == 0 && lowerBound > 0) {
// if The upper bound is 0 and the lower bound is positive
// it is a floating point and the lower bound is the number of bytes
rangeType = new DebugBaseType(name, (int) lowerBound, true);
} else if (lowerBound == -128 && upperBound == 127) {
// signed char;
rangeType = new DebugBaseType(name, 1, false);
} else if (self && lowerBound == 0 && upperBound == 127) {
// C/C++ specific
rangeType = new DebugBaseType(name, 1, false);
} else if (self && lowerBound == 0 && upperBound == 255) {
// unsigned char
rangeType = new DebugBaseType(name, 1, true);
} else if (lowerBound == -32768 && upperBound == 32767) {
// signed short
rangeType = new DebugBaseType(name, 2, false);
} else if (self && lowerBound == 0 && upperBound == 65535) {
// unsigned short
rangeType = new DebugBaseType(name, 2, true);
} else if (lowerBound == -2147483648 && upperBound == 2147483647) {
// int
rangeType = new DebugBaseType(name, 4, false);
}
}
return rangeType;
}
void parseStabConstant(IDebugEntryRequestor requestor, String name, String field, long value) {
try {
parseStabConstant(requestor, name, new StringReader(field), value);
} catch (IOException e) {
//
}
}
void parseStabConstant(IDebugEntryRequestor requestor, String name, Reader reader, long value) throws IOException {
int c = reader.read();
if (c == '=') {
c = reader.read();
switch (c) {
// Boolean constant.
// c=bvalue or c=bvalue
// value is a numeric value: 0 fo false and 1 for true.
// Not supported by GDB.
case 'b' :
break;
// Character constant.
// c=cvalue
// value is the numeric value of the constant.
// Not supported by GDB.
case 'c' :
break;
// Constant whose value van be represented as integral.
// c=e type-information, value
// type-information is the type of the constant.
// value is the numeric value of the constant.
// This is usually use for enumeration constants.
case 'e' :
{
int val = 0;
DebugType type = parseStabType("", reader); //$NON-NLS-1$
c = reader.read();
if (c == ',') {
StringBuffer sb = new StringBuffer();
while ((c = reader.read()) != -1) {
sb.append((char) c);
}
try {
String s = sb.toString();
val = Integer.decode(s).intValue();
} catch (NumberFormatException e) {
}
}
requestor.acceptTypeConst(name, type, val);
}
break;
// Integer constant.
// c=ivalue
// value is the numeric value;
case 'i' :
{
int val = 0;
StringBuffer sb = new StringBuffer();
while ((c = reader.read()) != -1) {
sb.append((char) c);
}
try {
String s = sb.toString();
val = Integer.decode(s).intValue();
} catch (NumberFormatException e) {
} catch (IndexOutOfBoundsException e) {
}
requestor.acceptIntegerConst(name, val);
}
break;
// Real constant.
// c=rvalue
// value is the real value, which can be INF or QNAN or SNAN
// preceded
// by a sign.
case 'r' :
{
double val = 0;
StringBuffer sb = new StringBuffer();
while ((c = reader.read()) != -1) {
sb.append((char) c);
}
try {
String s = sb.toString();
if (s.equals("-INF")) { //$NON-NLS-1$
val = Double.NEGATIVE_INFINITY;
} else if (s.equals("INF")) { //$NON-NLS-1$
val = Double.POSITIVE_INFINITY;
} else if (s.equals("QNAN")) { //$NON-NLS-1$
val = Double.NaN;
} else if (s.equals("SNAN")) { //$NON-NLS-1$
val = Double.NaN;
} else {
val = Double.parseDouble(s);
}
} catch (NumberFormatException e) {
} catch (IndexOutOfBoundsException e) {
}
requestor.acceptFloatConst(name, val);
}
break;
// String constant.
// c=svalue
// value is a strinc encosed in either ' in which case ' are
// escaped or
// " in which case " are escaped.
// Not supported by GDB.
case 's' :
break;
// Set constant.
// C/C++ does not have set
// Not supported by GDB.
case 'S' :
break;
}
}
}
DebugType getDebugType(TypeNumber tn) {
return mapTypes.get(tn);
}
public static void main(String[] args) {
try {
DebugSymsRequestor symreq = new DebugSymsRequestor();
Stabs stabs = new Stabs(args[0]);
stabs.parse(symreq);
DebugSym[] entries = symreq.getEntries();
for (DebugSym entry : entries) {
System.out.println(entry);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}