/******************************************************************************* * Copyright (c) 2006, 2010 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.ArrayList; import java.util.List; import org.eclipse.cdt.core.ISymbolReader; import org.eclipse.core.runtime.IProgressMonitor; public class StabsReader implements ISymbolReader { byte[] stabData; byte[] stabstrData; boolean isLe; boolean is64; List<String> fileList; String[] files = null; boolean parsed = false; String currentFile; public StabsReader(byte[] data, byte[] stabstr, boolean littleEndian) { this(data,stabstr,littleEndian,false); } /** * @since 5.2 */ public StabsReader(byte[] data, byte[] stabstr, boolean littleEndian, boolean is64bit) { stabData = data; stabstrData = stabstr; isLe = littleEndian; is64 = is64bit; fileList = new ArrayList<String>(); } public String[] getSourceFiles() { if (!parsed) { parse(); parsed = true; files = new String[fileList.size()]; for (int i = 0; i < fileList.size(); i++) { files[i] = 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 long read_8_bytes(byte[] bytes, int offset) throws IndexOutOfBoundsException { if (isLe) { return (((bytes[offset + 7] & 0xff) << 56) | ((bytes[offset +6] & 0xff) << 48) | ((bytes[offset +5] & 0xff) << 40) | ((bytes[offset +4] & 0xff) << 32) | ((bytes[offset +3] & 0xff) << 24) | ((bytes[offset +2] & 0xff) << 16) | ((bytes[offset +1] & 0xff) << 8) | (bytes[offset +0] & 0xff)); } return (((bytes[offset +0] & 0xff) << 56) | ((bytes[offset +1] & 0xff) << 48) | ((bytes[offset +2] & 0xff) << 40) | ((bytes[offset +3] & 0xff) << 32) | ((bytes[offset +4] & 0xff) << 24) | ((bytes[offset +5] & 0xff) << 16) | ((bytes[offset +6] & 0xff) << 8) | (bytes[offset +7] & 0xff)); } private String fixUpPath(String path) { // some compilers generate extra back slashes path = path.replaceAll("\\\\\\\\", "\\\\"); //$NON-NLS-1$//$NON-NLS-2$ // translate any cygwin drive paths, e.g. //G/System/main.cpp or /cygdrive/c/system/main.c if (path.startsWith("/cygdrive/") && ('/' == path.charAt(11))) { //$NON-NLS-1$ 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))) { //$NON-NLS-1$ 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() { int size = is64 ? StabConstant.SIZE_64 : StabConstant.SIZE; long nstab = stabData.length / 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 += 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 = is64 ? read_8_bytes(stabData, offset + 8) : 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; } } /** * @since 5.2 */ public String[] getSourceFiles(IProgressMonitor monitor) { return getSourceFiles(); } }