1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.tools.jaotc.binformat.macho; 25 26 import java.nio.ByteBuffer; 27 import java.nio.ByteOrder; 28 import java.util.ArrayList; 29 30 import jdk.tools.jaotc.binformat.macho.MachO; 31 import jdk.tools.jaotc.binformat.macho.MachO.symtab_command; 32 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; 33 import jdk.tools.jaotc.binformat.macho.MachOSymbol; 34 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; 35 36 public class MachOSymtab { 37 38 /** 39 * ByteBuffer holding the LC_SYMTAB command contents 40 */ 41 ByteBuffer symtabCmd; 42 43 /** 44 * ByteBuffer holding the symbol table entries and strings 45 */ 46 ByteBuffer symtabData; 47 48 int symtabDataSize; 49 50 ArrayList<MachOSymbol>localSymbols = new ArrayList<MachOSymbol>(); 51 ArrayList<MachOSymbol>globalSymbols = new ArrayList<MachOSymbol>(); 52 ArrayList<MachOSymbol>undefSymbols = new ArrayList<MachOSymbol>(); 53 54 /** 55 * number of symbols added 56 */ 57 int symbolCount; 58 59 /** 60 * String holding symbol table strings 61 */ 62 private StringBuilder strTabContent = new StringBuilder(); 63 64 /** 65 * Keeps track of bytes in string table since strTabContent.length() 66 * is number of chars, not bytes. 67 */ 68 private int strTabNrOfBytes = 0; 69 70 public MachOSymtab() { 71 symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize); 72 73 symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB); 74 symtabCmd.putInt(symtab_command.cmdsize.off, symtab_command.totalsize); 75 76 symbolCount = 0; 77 78 } 79 80 public int getAlign() { 81 return (4); 82 } 83 84 public MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) { 85 // Get the current symbol index and append symbol name to string table. 86 int index; 87 MachOSymbol sym; 88 89 if (name.isEmpty()) { 90 index = 0; 91 strTabContent.append('\0'); 92 strTabNrOfBytes += 1; 93 sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset); 94 localSymbols.add(sym); 95 } else { 96 // We can't trust strTabContent.length() since that is 97 // chars (UTF16), keep track of bytes on our own. 98 index = strTabNrOfBytes; 99 strTabContent.append("_").append(name).append('\0'); 100 // + 1 for null, + 1 for "_" 101 strTabNrOfBytes += (name.getBytes().length + 1 + 1); 102 103 sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset); 104 switch (type) { 105 case nlist_64.N_EXT: 106 undefSymbols.add(sym); 107 break; 108 case nlist_64.N_SECT: 109 case nlist_64.N_UNDF: // null symbol 110 localSymbols.add(sym); 111 break; 112 case nlist_64.N_SECT|nlist_64.N_EXT: 113 globalSymbols.add(sym); 114 break; 115 default: 116 System.out.println("Unsupported Symbol type " + type); 117 break; 118 } 119 } 120 symbolCount++; 121 return (sym); 122 } 123 124 public void setOffset(int symoff) { 125 symtabCmd.putInt(symtab_command.symoff.off, symoff); 126 } 127 128 // Update the symbol indexes once all symbols have been added. 129 // This is required since we'll be reordering the symbols in the 130 // file to be in the order of Local, global and Undefined. 131 public void updateIndexes() { 132 int index = 0; 133 134 // Update the local symbol indexes 135 for (int i = 0; i < localSymbols.size(); i++ ) { 136 MachOSymbol sym = localSymbols.get(i); 137 sym.setIndex(index++); 138 } 139 140 // Update the global symbol indexes 141 for (int i = 0; i < globalSymbols.size(); i++ ) { 142 MachOSymbol sym = globalSymbols.get(i); 143 sym.setIndex(index++); 144 } 145 146 // Update the undefined symbol indexes 147 for (int i = index; i < undefSymbols.size(); i++ ) { 148 MachOSymbol sym = undefSymbols.get(i); 149 sym.setIndex(index++); 150 } 151 } 152 153 // Update LC_SYMTAB command fields based on the number of symbols added 154 // return the file size taken up by symbol table entries and strings 155 public int calcSizes() { 156 int stroff; 157 158 stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount); 159 symtabCmd.putInt(symtab_command.nsyms.off, symbolCount); 160 symtabCmd.putInt(symtab_command.stroff.off, stroff); 161 symtabCmd.putInt(symtab_command.strsize.off, strTabNrOfBytes); 162 symtabDataSize = (nlist_64.totalsize * symbolCount) + strTabNrOfBytes; 163 164 return (symtabDataSize); 165 } 166 167 public int getNumLocalSyms() { return localSymbols.size(); } 168 public int getNumGlobalSyms() { return globalSymbols.size(); } 169 public int getNumUndefSyms() { return undefSymbols.size(); } 170 171 public byte[] getCmdArray() { 172 return symtabCmd.array(); 173 } 174 175 // Create a single byte array that contains the symbol table entries 176 // and string table 177 public byte[] getDataArray() { 178 int index = 0; 179 symtabData = MachOByteBuffer.allocate(symtabDataSize); 180 byte [] retarray; 181 182 // Add the local symbols 183 for (int i = 0; i < localSymbols.size(); i++ ) { 184 MachOSymbol sym = localSymbols.get(i); 185 byte [] arr = sym.getArray(); 186 symtabData.put(arr); 187 } 188 // Add the global symbols 189 for (int i = 0; i < globalSymbols.size(); i++ ) { 190 MachOSymbol sym = globalSymbols.get(i); 191 byte [] arr = sym.getArray(); 192 symtabData.put(arr); 193 } 194 // Add the undefined symbols 195 for (int i = 0; i < undefSymbols.size(); i++ ) { 196 MachOSymbol sym = undefSymbols.get(i); 197 byte [] arr = sym.getArray(); 198 symtabData.put(arr); 199 } 200 201 // Add the stringtable 202 byte [] strs = strTabContent.toString().getBytes(); 203 symtabData.put(strs); 204 205 retarray = symtabData.array(); 206 207 return (retarray); 208 } 209 } 210 211