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.util.ArrayList; 28 29 import jdk.tools.jaotc.binformat.macho.MachO.symtab_command; 30 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; 31 import jdk.tools.jaotc.binformat.macho.MachOSymbol; 32 import jdk.tools.jaotc.binformat.macho.MachOByteBuffer; 33 34 final class MachOSymtab { 35 36 /** 37 * ByteBuffer holding the LC_SYMTAB command contents 38 */ 39 private final ByteBuffer symtabCmd; 40 41 private int symtabDataSize; 42 43 private final ArrayList<MachOSymbol> localSymbols = new ArrayList<>(); 44 private final ArrayList<MachOSymbol> globalSymbols = new ArrayList<>(); 45 private final ArrayList<MachOSymbol> undefSymbols = new ArrayList<>(); 46 47 /** 48 * number of symbols added 49 */ 50 private int symbolCount; 51 52 /** 53 * String holding symbol table strings 54 */ 55 private final StringBuilder strTabContent = new StringBuilder(); 56 57 /** 58 * Keeps track of bytes in string table since strTabContent.length() is number of chars, not bytes. 59 */ 60 private int strTabNrOfBytes = 0; 61 62 MachOSymtab() { 63 symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize); 64 65 symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB); 66 symtabCmd.putInt(symtab_command.cmdsize.off, symtab_command.totalsize); 67 68 symbolCount = 0; 69 70 } 71 72 static int getAlign() { 73 return (4); 74 } 75 76 MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) { 77 // Get the current symbol index and append symbol name to string table. 78 int index; 79 MachOSymbol sym; 80 81 if (name.isEmpty()) { 82 index = 0; 83 strTabContent.append('\0'); 84 strTabNrOfBytes += 1; 85 sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset); 86 localSymbols.add(sym); 87 } else { 88 // We can't trust strTabContent.length() since that is 89 // chars (UTF16), keep track of bytes on our own. 90 index = strTabNrOfBytes; 91 strTabContent.append("_").append(name).append('\0'); 92 // + 1 for null, + 1 for "_" 93 strTabNrOfBytes += (name.getBytes().length + 1 + 1); 94 95 sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset); 96 switch (type) { 97 case nlist_64.N_EXT: 98 undefSymbols.add(sym); 99 break; 100 case nlist_64.N_SECT: 101 case nlist_64.N_UNDF: // null symbol 102 localSymbols.add(sym); 103 break; 104 case nlist_64.N_SECT | nlist_64.N_EXT: 105 globalSymbols.add(sym); 106 break; 107 default: 108 System.out.println("Unsupported Symbol type " + type); 109 break; 110 } 111 } 112 symbolCount++; 113 return (sym); 114 } 115 116 void setOffset(int symoff) { 117 symtabCmd.putInt(symtab_command.symoff.off, symoff); 118 } 119 120 // Update the symbol indexes once all symbols have been added. 121 // This is required since we'll be reordering the symbols in the 122 // file to be in the order of Local, global and Undefined. 123 void updateIndexes() { 124 int index = 0; 125 126 // Update the local symbol indexes 127 for (int i = 0; i < localSymbols.size(); i++) { 128 MachOSymbol sym = localSymbols.get(i); 129 sym.setIndex(index++); 130 } 131 132 // Update the global symbol indexes 133 for (int i = 0; i < globalSymbols.size(); i++) { 134 MachOSymbol sym = globalSymbols.get(i); 135 sym.setIndex(index++); 136 } 137 138 // Update the undefined symbol indexes 139 for (int i = index; i < undefSymbols.size(); i++) { 140 MachOSymbol sym = undefSymbols.get(i); 141 sym.setIndex(index++); 142 } 143 } 144 145 // Update LC_SYMTAB command fields based on the number of symbols added 146 // return the file size taken up by symbol table entries and strings 147 int calcSizes() { 148 int stroff; 149 150 stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount); 151 symtabCmd.putInt(symtab_command.nsyms.off, symbolCount); 152 symtabCmd.putInt(symtab_command.stroff.off, stroff); 153 symtabCmd.putInt(symtab_command.strsize.off, strTabNrOfBytes); 154 symtabDataSize = (nlist_64.totalsize * symbolCount) + strTabNrOfBytes; 155 156 return (symtabDataSize); 157 } 158 159 int getNumLocalSyms() { 160 return localSymbols.size(); 161 } 162 163 int getNumGlobalSyms() { 164 return globalSymbols.size(); 165 } 166 167 int getNumUndefSyms() { 168 return undefSymbols.size(); 169 } 170 171 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 byte[] getDataArray() { 178 ByteBuffer symtabData = MachOByteBuffer.allocate(symtabDataSize); 179 byte[] retarray; 180 181 // Add the local symbols 182 for (int i = 0; i < localSymbols.size(); i++) { 183 MachOSymbol sym = localSymbols.get(i); 184 byte[] arr = sym.getArray(); 185 symtabData.put(arr); 186 } 187 // Add the global symbols 188 for (int i = 0; i < globalSymbols.size(); i++) { 189 MachOSymbol sym = globalSymbols.get(i); 190 byte[] arr = sym.getArray(); 191 symtabData.put(arr); 192 } 193 // Add the undefined symbols 194 for (int i = 0; i < undefSymbols.size(); i++) { 195 MachOSymbol sym = undefSymbols.get(i); 196 byte[] arr = sym.getArray(); 197 symtabData.put(arr); 198 } 199 200 // Add the stringtable 201 byte[] strs = strTabContent.toString().getBytes(); 202 symtabData.put(strs); 203 204 retarray = symtabData.array(); 205 206 return (retarray); 207 } 208 }