blob: 5253ca2a27c03d0505a64d290f7d3e08084e0504 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.utils.stabs;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.cdt.utils.elf.Elf;
public class Stabs {
byte[] stabData;
byte[] stabstrData;
boolean isLe;
Entry[] entries;
public class Entry implements Comparable{
public long addr;
public long size;
public int startLine;
public String string;
public Entry(String s) {
string = s;
}
public int compareTo(Object obj) {
long thisVal = 0;
long anotherVal = 0;
if (obj instanceof Entry) {
Entry entry = (Entry) obj;
thisVal = this.addr;
anotherVal = entry.addr;
} else if (obj instanceof Long) {
Long val = (Long) obj;
anotherVal = val.longValue();
thisVal = (long) this.addr;
}
return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Name: ").append(string).append("\n");
buf.append("\taddress:").append("0x").append(Long.toHexString(addr)).append("\n");
buf.append("\tstartLine:").append(startLine).append("\n");
//buf.append("\tName:").append(string).append("\n");
return buf.toString();
}
}
public abstract class LocatableEntry extends Entry {
public String filename;
public LocatableEntry(String s) {
super(s);
}
}
public class Variable extends LocatableEntry {
public int kind;
public Function function;
public Variable(String s) {
super(s);
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Variable: ");
buf.append(super.toString());
buf.append("\tkind:").append(kind).append("\n");
buf.append("\tfilename:").append(filename).append("\n");
return buf.toString();
}
}
public class Function extends LocatableEntry {
public int endLine;
public ArrayList lines;
public ArrayList variables;
public Function(String s) {
super(s);
variables = new ArrayList();
lines = new ArrayList();
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("Function: ");
buf.append(super.toString());
buf.append("\tendLine:").append(endLine).append("\n");
buf.append("\tfilename:").append(filename).append("\n");
buf.append("\tSource code: ");
for (int i = 0; i < lines.size(); i++) {
buf.append(" ").append(lines.get(i));
}
buf.append("\n");
buf.append("\tVariables\n");
for (int i = 0; i < variables.size(); i++) {
buf.append("\t\t").append("[" + i + "]").append("\n");
buf.append("\t\t\t").append(variables.get(i)).append("\n");
}
return buf.toString();
}
}
public class Include extends Entry {
int index;
public Include(String s) {
super(s);
}
public String toString() {
return super.toString() + "\tindex:" + index + "\n";
}
}
// type-information = type-number | type-definition
// type-number = type-reference
// type-reference = number | '(' number ',' number ')'
// type-definition = type_number '=' (type-descriptor | type-reference)
public class TypeInformation {
int typeNumber;
int fileNumber;
boolean isTypeDefinition;
public TypeInformation(String s) {
parserTypeInformation(s.toCharArray());
}
void parserTypeInformation(char[] array) {
}
}
/**
* Format: string_field = name ':' symbol-descriptor type-information
*/
public class StringField {
String name;
char symbolDescriptor;
String typeInformation;
public StringField(String s) {
parseStringField(s.toCharArray());
}
/**
* Format: string_field = name ':' symbol-descriptor type-information
*/
void parseStringField(char[] array) {
int index = 0;
// Some String field may contain format like:
// "foo::bar::baz:t5=*6" in that case the name is "foo::bar::baz"
char prev = 0;
for (int i = 0; index < array.length; index++) {
char c = array[index];
if (prev != ':') {
break;
}
prev = c;
}
if (index < array.length) {
name = new String(array, 0, index);
} else {
name = new String(array);
}
// get the symbol descriptor
if (index < array.length) {
index++;
symbolDescriptor = array[index];
}
// get the type-information
if (index < array.length) {
typeInformation = new String(array, index, array.length);
} else {
typeInformation = new String();
}
}
}
public 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();
}
public Stabs(byte[] stab, byte[] stabstr, boolean le) {
stabData = stab;
stabstrData = stabstr;
isLe = le;
}
public Entry[] getEntries() throws IOException {
if (entries == null) {
parse();
}
return entries;
}
public Entry getEntry(long addr) throws IOException {
if (entries == null) {
parse();
}
int insertion = Arrays.binarySearch(entries, new Long(addr));
if (insertion >= 0) {
return entries[insertion];
}
if (insertion == -1) {
return null;
}
insertion = -insertion - 1;
Entry entry = entries[insertion - 1];
if (addr < (entry.addr + entry.size)) {
return entries[insertion - 1];
}
return null;
}
void parse() throws IOException {
List list = new ArrayList();
long nstab = stabData.length / StabConstant.SIZE;
int i, offset, bracket;
int includeCount = 0;
Function currentFunction = null;
String currentFile = "";
String holder = null;
for (bracket = i = offset = 0; i < nstab; i++, offset += StabConstant.SIZE) {
long stroff = 0;
int type = 0;
int other = 0;
short desc = 0;
long value = 0;
String name = new String();
// get the offset for the string; 4 bytes
if (isLe) {
stroff =
(((stabData[offset + 3] & 0xff) << 24)
+ ((stabData[offset + 2] & 0xff) << 16)
+ ((stabData[offset + 1] & 0xff) << 8)
+ (stabData[offset] & 0xff));
} else {
stroff =
(((stabData[offset] & 0xff) << 24)
+ ((stabData[offset + 1] & 0xff) << 16)
+ ((stabData[offset + 2] & 0xff) << 8)
+ (stabData[offset + 3] & 0xff));
}
if (stroff > 0) {
name = makeString(stroff);
}
// 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 (name.endsWith("\\") || name.endsWith("?")) {
name = name.substring(0, name.length() - 1);
if (holder == null) {
holder = name;
} else {
holder += name;
}
continue;
} else if (holder != null) {
name = holder + name;
holder = null;
}
/* FIXME: Sometimes the special C++ names start with '.'. */
if (name.length() > 1 && name.charAt(0) == '$') {
switch (name.charAt(1)) {
case 't' :
name = "this";
break;
case 'v' :
/* Was: name = "vptr"; */
break;
case 'e' :
name = "eh_throw";
break;
case '_' :
/* This was an anonymous type that was never fixed up. */
break;
case 'X' :
/* SunPRO (3.0 at least) static variable encoding. */
break;
default :
name = "unknown C++ encoded name";
break;
}
}
// get the type; 1 byte;
type = 0xff & stabData[offset + 4];
// get the other
other = 0xff & stabData[offset + 5];
// get the desc
if (isLe) {
desc = (short) (((stabData[offset + 7] & 0xff) << 8) + (stabData[offset + 6] & 0xff));
} else {
desc = (short) (((stabData[offset + 6] & 0xff) << 8) + (stabData[offset + 7] & 0xff));
}
// get the value
if (isLe) {
value =
(((stabData[offset + 11] & 0xff) << 24)
+ ((stabData[offset + 10] & 0xff) << 16)
+ ((stabData[offset + 9] & 0xff) << 8)
+ (stabData[offset + 8] & 0xff));
} else {
value =
(((stabData[offset + 8] & 0xff) << 24)
+ ((stabData[offset + 9] & 0xff) << 16)
+ ((stabData[offset + 10] & 0xff) << 8)
+ (stabData[offset + 11] & 0xff));
}
// Parse the string
switch (type) {
case StabConstant.N_GSYM :
case StabConstant.N_LSYM :
case StabConstant.N_PSYM :
Variable variable = new Variable(name);
variable.kind = type;
variable.addr = value;
variable.startLine = desc;
variable.function = currentFunction;
variable.filename = currentFile;
list.add(variable);
if (currentFunction != null) {
currentFunction.variables.add(variable);
}
break;
case StabConstant.N_SLINE :
if (currentFunction != null) {
if (currentFunction.startLine == 0) {
currentFunction.endLine = currentFunction.startLine = desc;
} else {
currentFunction.endLine = desc;
currentFunction.size = value;
}
currentFunction.lines.add(new Integer(desc));
}
break;
case StabConstant.N_FUN :
if (name.length() == 0) {
name = "anon";
}
currentFunction = null;
currentFunction = new Function(name);
currentFunction.addr = value;
currentFunction.startLine = desc;
currentFunction.filename = currentFile;
list.add(currentFunction);
break;
case StabConstant.N_LBRAC :
bracket++;
break;
case StabConstant.N_RBRAC :
bracket--;
break;
case StabConstant.N_BINCL :
Include include = new Include(name);
include.index = includeCount++;
list.add(include);
break;
case StabConstant.N_EINCL :
break;
case StabConstant.N_SO :
if (name.length() == 0) {
currentFile = name;
} else {
if (currentFile != null && currentFile.endsWith("/")) {
currentFile += name;
} else {
currentFile = name;
}
}
break;
}
//System.out.println(" " + i + "\t" + Stab.type2String(type) + "\t" + other + "\t\t" +
// desc + "\t" + Long.toHexString(value) + "\t" + + stroff + "\t\t" +name);
}
entries = new Entry[list.size()];
list.toArray(entries);
list.clear();
Arrays.sort(entries);
}
public void print() {
for (int i = 0; i < entries.length; i++) {
Entry entry = entries[i];
System.out.println(entry);
}
}
public static void main(String[] args) {
try {
Elf.Section stab = null;
Elf.Section stabstr = null;
Elf exe = new Elf(args[0]);
Elf.Section[] sections = exe.getSections();
for (int i = 0; i < sections.length; i++) {
String name = sections[i].toString();
if (name.equals(".stab")) {
stab = sections[i];
} else if (name.equals(".stabstr")) {
stabstr = sections[i];
}
}
if (stab != null && stabstr != null) {
long nstab = stab.sh_size / StabConstant.SIZE;
System.out.println("Number of stabs" + nstab);
byte[] array = stab.loadSectionData();
byte[] strtab = stabstr.loadSectionData();
Stabs stabs = new Stabs(array, strtab, true);
stabs.parse();
stabs.print();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}