/******************************************************************************* * Copyright (c) 2004, 2008 IBM Corporation 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: * IBM - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.utils.som; import java.io.EOFException; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.utils.coff.ReadMemoryAccess; /** * Representation of a HP-UX SOM binary format * * @author vhirsl */ public class SOM { public static final String NL = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ String filename; FileHeader filehdr; RandomAccessFile rfile; long startingOffset; byte[] string_table; Symbol[] symbols; /** * SOM Header record * * @author vhirsl */ public static class FileHeader { public final static int FILHSZ = 32*4; // Consts public static final short PA_RISC_10 = 0x20b; public static final short PA_RISC_11 = 0x210; public static final short PA_RISC_20 = 0x214; public static final short EXE_SOM_LIB = 0x104; // executable SOM library public static final short REL_SOM = 0x106; // relocatable SOM public static final short PRIV_EXEC_SOM = 0x107; // non-sharable, executable SOM public static final short SHARE_EXEC_SOM = 0x108; // sharable, executable SOM public static final short SHARE_DEMAND_LOAD_EXE_SOM = 0x10b; // sharable, demand-loadable executable SOM public static final short DYN_LOAD_LIB = 0x10d; // dynamic load library public static final short SHARED_LIB = 0x10e; // shared library public static final short RELOC_SOM_LIB = 0x619; // relocatable SOM library // Fields public short system_id; // magic number - system public short a_magic; // magic number - file type public int version_id; // version id; format = YYMMDDHH public long file_time_sec; // system clock - zero if unused public long file_time_nano; // system clock - zero if unused public int entry_space; // index of space containing entry point public int entry_subspace; // index of subspace for entry point public int entry_offset; // offset of entry point public int aux_header_location; // auxiliary header location public int aux_header_size; // auxiliary header size public int som_length; // length in bytes of entire som public int presumed_dp; // DP value assumed during compilation public int space_location; // location in file of space dictionary public int space_total; // number of space entries public int subspace_location; // location of subspace entries public int subspace_total; // number of subspace entries public int loader_fixup_location; // MPE/iX loader fixup public int loader_fixup_total; // number of loader fixup records public int space_strings_location; // file location of string area for space and subspace names public int space_strings_size; // size of string area for space and subspace names public int init_array_location; // reserved for use by system public int init_array_total; // reserved for use by system public int compiler_location; // location in file of module dictionary public int compiler_total; // number of modules public int symbol_location; // location in file of symbol dictionary public int symbol_total; // number of symbol records public int fixup_request_location; // location in file of fix-up requests public int fixup_request_total; // number of fixup requests public int symbol_strings_location; // file location of string area for module and symbol names public int symbol_strings_size; // size of string area for module and symbol names public int unloadable_sp_location; // byte offset of first byte of datafor unloadable spaces public int unloadable_sp_size; // byte length of data for unloadable spaces public int checksum; public FileHeader (RandomAccessFile file) throws IOException { this(file, file.getFilePointer()); } public FileHeader (RandomAccessFile file, long offset) throws IOException { file.seek(offset); byte[] hdr = new byte[FILHSZ]; file.readFully(hdr); commonSetup(hdr, false); } public FileHeader (byte[] hdr, boolean little) throws IOException { commonSetup(hdr, little); } public void commonSetup(byte[] hdr, boolean little) throws IOException { if (hdr == null || hdr.length < FILHSZ) { throw new EOFException(CCorePlugin.getResourceString("Util.exception.arrayToSmall")); //$NON-NLS-1$ } if (!isSOMHeader(hdr)) { throw new IOException(CCorePlugin.getResourceString("Util.exception.notSOM")); //$NON-NLS-1$ } ReadMemoryAccess memory = new ReadMemoryAccess(hdr, little); system_id = memory.getShort(); a_magic = memory.getShort(); version_id = memory.getInt(); file_time_sec = memory.getInt(); file_time_nano = memory.getInt(); entry_space = memory.getInt(); entry_subspace = memory.getInt(); entry_offset = memory.getInt(); aux_header_location = memory.getInt(); aux_header_size = memory.getInt(); som_length = memory.getInt(); presumed_dp = memory.getInt(); space_location = memory.getInt(); space_total = memory.getInt(); subspace_location = memory.getInt(); subspace_total = memory.getInt(); loader_fixup_location = memory.getInt(); loader_fixup_total = memory.getInt(); space_strings_location = memory.getInt(); space_strings_size = memory.getInt(); init_array_location = memory.getInt(); init_array_total = memory.getInt(); compiler_location = memory.getInt(); compiler_total = memory.getInt(); symbol_location = memory.getInt(); symbol_total = memory.getInt(); fixup_request_location = memory.getInt(); fixup_request_total = memory.getInt(); symbol_strings_location = memory.getInt(); symbol_strings_size = memory.getInt(); unloadable_sp_location = memory.getInt(); unloadable_sp_size = memory.getInt(); checksum = memory.getInt(); } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("FILE HEADER VALUES").append(NL); //$NON-NLS-1$ buffer.append("system_id = ").append(system_id).append(NL); //$NON-NLS-1$ buffer.append("a_magic = ").append(a_magic).append(NL); //$NON-NLS-1$ buffer.append("version_id = ").append(version_id).append(NL); //$NON-NLS-1$ buffer.append("file_time_sec = ").append(file_time_sec).append(NL); //$NON-NLS-1$ buffer.append("file_time_nano = ").append(file_time_nano).append(NL); //$NON-NLS-1$ buffer.append("entry_space = ").append(entry_space).append(NL); //$NON-NLS-1$ buffer.append("entry_subspace = ").append(entry_subspace).append(NL); //$NON-NLS-1$ buffer.append("aux_header_location = ").append(aux_header_location).append(NL); //$NON-NLS-1$ buffer.append("aux_header_size = ").append(aux_header_size).append(NL); //$NON-NLS-1$ buffer.append("som_length = ").append(som_length).append(NL); //$NON-NLS-1$ buffer.append("presumed_dp = ").append(presumed_dp).append(NL); //$NON-NLS-1$ buffer.append("space_location = ").append(space_location).append(NL); //$NON-NLS-1$ buffer.append("space_total = ").append(space_total).append(NL); //$NON-NLS-1$ buffer.append("subspace_location = ").append(subspace_location).append(NL); //$NON-NLS-1$ buffer.append("subspace_total = ").append(subspace_total).append(NL); //$NON-NLS-1$ buffer.append("loader_fixup_location = ").append(loader_fixup_location).append(NL); //$NON-NLS-1$ buffer.append("loader_fixup_total = ").append(loader_fixup_total).append(NL); //$NON-NLS-1$ buffer.append("space_strings_location = ").append(space_strings_location).append(NL); //$NON-NLS-1$ buffer.append("space_strings_size = ").append(space_strings_size).append(NL); //$NON-NLS-1$ buffer.append("init_array_location = ").append(init_array_location).append(NL); //$NON-NLS-1$ buffer.append("init_array_total = ").append(init_array_total).append(NL); //$NON-NLS-1$ buffer.append("compiler_location = ").append(compiler_location).append(NL); //$NON-NLS-1$ buffer.append("compiler_total = ").append(compiler_total).append(NL); //$NON-NLS-1$ buffer.append("symbol_location = ").append(symbol_location).append(NL); //$NON-NLS-1$ buffer.append("symbol_total = ").append(symbol_total).append(NL); //$NON-NLS-1$ buffer.append("fixup_request_location = ").append(fixup_request_location).append(NL); //$NON-NLS-1$ buffer.append("fixup_request_total = ").append(fixup_request_total).append(NL); //$NON-NLS-1$ buffer.append("symbol_strings_location = ").append(symbol_strings_location).append(NL); //$NON-NLS-1$ buffer.append("symbol_strings_size = ").append(symbol_strings_size).append(NL); //$NON-NLS-1$ buffer.append("unloadable_sp_location = ").append(unloadable_sp_location).append(NL); //$NON-NLS-1$ buffer.append("unloadable_sp_size = ").append(unloadable_sp_size).append(NL); //$NON-NLS-1$ buffer.append("checksum = ").append(checksum).append(NL); //$NON-NLS-1$ return buffer.toString(); } } public class Symbol { public static final int SYMSZ = 5*4; // 5 words = 20 bytes // masks // NOTE: HP-UX denotes bit 0 as a leftmost bit in a word // following representation denotes bit 0 as a rightmost bit in a word public static final int B31_MASK = 0x80000000; public static final int B30_MASK = 0x40000000; public static final int B29_24_MASK = 0x3f000000; public static final int B23_20_MASK = 0x00f00000; public static final int B19_17_MASK = 0x000e0000; public static final int B16_MASK = 0x00010000; public static final int B15_MASK = 0x00008000; public static final int B14_MASK = 0x00004000; public static final int B13_MASK = 0x00002000; public static final int B12_MASK = 0x00001000; public static final int B11_10_MASK = 0x00000C00; public static final int B9_0_MASK = 0x000003ff; public static final int B23_0_MASK = 0x00ffffff; public static final int B7_0_MASK = 0x000000ff; // symbol type public static final int NULL = 0; // Invalid symbol record public static final int ABSOLUTE = 1; // Absolute constant public static final int DATA = 2; // Normal initialized data public static final int CODE = 3; // Unspecified code public static final int PRI_PROG = 4; // Primary program entry point public static final int SEC_PROG = 5; // Secondary program entry point public static final int ENTRY = 6; // Any code entry point public static final int STORAGE = 7; // Uninitialized common data blocks public static final int STUB = 8; // Import external call stub or a parameter relocation stub public static final int MODULE = 9; // Source module name public static final int SYM_EXT = 10; // Extension record of the current entry public static final int ARG_EXT = 11; // -||- public static final int MILLICODE = 12; // Millicode routine public static final int PLABEL = 13; // Export stub for a procedure public static final int OCT_DIS = 14; // Pointer to translated code segment exists but disabled public static final int MILLI_EXT = 15; // Address of an external millicode routine public static final int ST_DATA = 15; // Thread specific data // symbol scope public static final int UNSAT = 0; // Import request that has not been satisfied public static final int EXTERNAL = 1; // Import request linked to a symbol in another SOM public static final int LOCAL = 2; // The symbol is not exported for use outside the SOM public static final int UNIVERSAL = 3; // The symbol is exported for use outside the SOM // fields public boolean hidden; // W1 b31 public boolean secondary_def; // W1 b30 public int symbol_type; // W1 b29-24 public int symbol_scope; // W1 b23-20 public int check_level; // W1 b19-17 public boolean must_qualify; // W1 b16 public boolean initially_frozen; // W1 b15 public boolean memory_resident; // W1 b14 public boolean is_common; // W1 b13 public boolean dup_common; // W1 b12 public int xleast; // W1 b11-10 public int arg_reloc; // W1 b9-0 public int name_offset; // W2 public int qualifier_name_offset; // W3 public boolean has_long_return; // W4 b31 public boolean no_relocation; // W4 b30 public int symbol_info; // W4 b23-0 public int symbol_value; // W5 public Symbol(RandomAccessFile file) throws IOException { this(file, file.getFilePointer()); } public Symbol(RandomAccessFile file, long offset) throws IOException { file.seek(offset); byte[] bytes = new byte[SYMSZ]; file.readFully(bytes); ReadMemoryAccess memory = new ReadMemoryAccess(bytes, false); // big endian // first word int word = memory.getInt(); hidden = (word & B31_MASK) != 0; secondary_def = (word & B30_MASK) != 0; symbol_type = (word & B29_24_MASK) >> 24; symbol_scope = (word & B23_20_MASK) >> 20; check_level = (word & B19_17_MASK) >> 17; must_qualify = (word & B16_MASK) != 0; initially_frozen = (word & B15_MASK) != 0; memory_resident = (word & B14_MASK) != 0; is_common = (word & B13_MASK) != 0; dup_common = (word & B12_MASK) != 0; xleast = (word & B11_10_MASK) >> 10; arg_reloc = word & B9_0_MASK; // second word name_offset = memory.getInt(); // third word qualifier_name_offset = memory.getInt(); // fourth word word = memory.getInt(); has_long_return = (word & B31_MASK) != 0; no_relocation = (word & B30_MASK) != 0; symbol_info = word & B23_0_MASK; // fifth word symbol_value = memory.getInt(); // check for symbol extension record and descriptor array records if (check_level >= 1) { // bytes = new byte[SYMSZ]; file.readFully(bytes); memory = new ReadMemoryAccess(bytes, false); // big endian // an extension record is present (size 5 words = 20 bytes) word = memory.getInt(); int num_args = word & B7_0_MASK; // check for argument descriptor arrays if (num_args > 3 && check_level >=3) { int num_descs = (num_args-3)%4 == 0 ? (num_args-3)/4 : (num_args-3)/4 + 1; for (int i = 0; i < num_descs; ++ i) { file.readFully(bytes); } } } } public String getName(byte[] table) { if (qualifier_name_offset != 0) { byte[] len = new byte[4]; System.arraycopy(table, qualifier_name_offset-4, len, 0, 4); ReadMemoryAccess memory = new ReadMemoryAccess(len, false); // big endian int length = memory.getInt(); return new String(table, qualifier_name_offset, length); } if (name_offset != 0) { byte[] len = new byte[4]; System.arraycopy(table, name_offset-4, len, 0, 4); ReadMemoryAccess memory = new ReadMemoryAccess(len, false); // big endian int length = memory.getInt(); return new String(table, name_offset, length); } return ""; //$NON-NLS-1$ } public boolean isFunction() { return (symbol_type == PRI_PROG || (symbol_type == ENTRY && symbol_scope != LOCAL)); } public boolean isVariable() { return ((symbol_type == DATA && symbol_scope != LOCAL) || symbol_type == STORAGE); } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("SYMBOL TABLE ENTRY").append(NL); //$NON-NLS-1$ buffer.append("symbol_name = "); //$NON-NLS-1$ try { buffer.append(getName(getStringTable())).append(NL); } catch (IOException e) { buffer.append("I/O error"); //$NON-NLS-1$ } buffer.append("symbol_value = ").append(symbol_value).append(NL); //$NON-NLS-1$ buffer.append("symbol_type = ").append(symbol_type).append(NL); //$NON-NLS-1$ buffer.append("symbol_scope = ").append(symbol_scope).append(NL); //$NON-NLS-1$ return buffer.toString(); } } public static class Attribute { public static final int SOM_TYPE_EXE = 1; public static final int SOM_TYPE_SHLIB = 2; public static final int SOM_TYPE_OBJ = 3; public static final int SOM_TYPE_CORE = 4; String cpu; int type; boolean bDebug; boolean isle; public String getCPU() { return cpu; } public int getType() { return type; } public boolean hasDebug() { return bDebug; } public boolean isLittleEndian() { return isle; } } /* * SOM class implementation */ // A hollow entry, to be used with caution in controlled situations protected SOM() { } public SOM(String filename) throws IOException { this(filename, 0); } public SOM(String filename, long offset) throws IOException { this.filename = filename; commonSetup(new RandomAccessFile(filename, "r"), offset); //$NON-NLS-1$ } void commonSetup(RandomAccessFile file, long offset) throws IOException { startingOffset = offset; rfile = file; try { filehdr = new FileHeader(rfile, startingOffset); } finally { dispose(); } } public void dispose() throws IOException { if (rfile != null) { rfile.close(); rfile = null; } } RandomAccessFile getRandomAccessFile () throws IOException { if (rfile == null) { rfile = new RandomAccessFile(filename, "r"); //$NON-NLS-1$ } return rfile; } public FileHeader getFileHeader() throws IOException { return filehdr; } public Attribute getAttributes() { Attribute attrib = new Attribute(); // Machine type. switch (filehdr.system_id) { case FileHeader.PA_RISC_10: case FileHeader.PA_RISC_11: case FileHeader.PA_RISC_20: attrib.cpu = "PA_RISC"; //$NON-NLS-1$ break; default: attrib.cpu = "unknown"; //$NON-NLS-1$ } /* SOM characteristics, FileHeader.a_magic. */ switch (filehdr.a_magic) { case FileHeader.EXE_SOM_LIB: case FileHeader.PRIV_EXEC_SOM: case FileHeader.SHARE_EXEC_SOM: case FileHeader.SHARE_DEMAND_LOAD_EXE_SOM: attrib.type = Attribute.SOM_TYPE_EXE; break; case FileHeader.DYN_LOAD_LIB: case FileHeader.SHARED_LIB: attrib.type = Attribute.SOM_TYPE_SHLIB; break; default: attrib.type = Attribute.SOM_TYPE_OBJ; } // For HP-UX SOM always assume big endian unless otherwise. attrib.isle = false; // No debug information. if (filehdr.symbol_location == 0 && filehdr.symbol_total == 0) { attrib.bDebug = false; } else { attrib.bDebug = true; } return attrib; } public Symbol[] getSymbols() throws IOException { if (symbols == null) { long offset = startingOffset + getFileHeader().symbol_location; getRandomAccessFile(); rfile.seek(offset); int numSymbols = getFileHeader().symbol_total; ArrayList<Symbol> symList = new ArrayList<Symbol>(numSymbols); for (int i = 0; i < numSymbols; ++i) { Symbol v = new Symbol(rfile); symList.add(v); } symbols = symList.toArray(new Symbol[symList.size()]); } return symbols; } public byte[] getStringTable() throws IOException { if (string_table == null) { if (getFileHeader().symbol_strings_size > 0) { getRandomAccessFile(); long offset = startingOffset+ getFileHeader().symbol_strings_location; rfile.seek(offset); string_table = new byte[getFileHeader().symbol_strings_size]; rfile.readFully(string_table); } else { string_table = new byte[0]; } } return string_table; } @Override public String toString() { StringBuffer buffer = new StringBuffer(); try { FileHeader header = null; header = getFileHeader(); if (header != null) { buffer.append(header); } getSymbols(); for (int i = 0; i < symbols.length; ++i) { buffer.append(symbols[i]); } } catch (IOException e) { e.printStackTrace(); } return buffer.toString(); } public static boolean isSOMHeader(byte[] hints) { if (hints != null && hints[0] == 0x02 && (hints[1] == (byte)0xb || hints[1] == (byte)0x10 || hints[1] == (byte)0x14) ) { return true; } return false; } public static Attribute getAttributes(byte[] hints) throws IOException { SOM emptyXCoff = new SOM(); emptyXCoff.filehdr = new SOM.FileHeader(hints, false); // big endian Attribute attribute = emptyXCoff.getAttributes(); emptyXCoff.dispose(); return attribute; } public static Attribute getAttributes(String file) throws IOException { SOM xcoff = new SOM(file); Attribute attribute = xcoff.getAttributes(); xcoff.dispose(); return attribute; } public static void main(String[] args) { try { SOM som = new SOM(args[0]); System.out.println(som); } catch (IOException e) { e.printStackTrace(); } } }