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