1 /* 2 * Copyright (c) 2017, 2018, 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 25 26 package jdk.tools.jaotc.binformat.macho; 27 28 import java.nio.ByteBuffer; 29 import java.util.ArrayList; 30 31 import jdk.tools.jaotc.binformat.macho.MachO.nlist_64; 32 import jdk.tools.jaotc.binformat.macho.MachO.symtab_command; 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 59 * bytes. 60 */ 61 private int strTabNrOfBytes = 0; 62 63 MachOSymtab() { 64 symtabCmd = MachOByteBuffer.allocate(symtab_command.totalsize); 65 66 symtabCmd.putInt(symtab_command.cmd.off, symtab_command.LC_SYMTAB); 67 symtabCmd.putInt(symtab_command.cmdsize.off, symtab_command.totalsize); 68 69 symbolCount = 0; 70 71 } 72 73 static int getAlign() { 74 return (4); 75 } 76 77 MachOSymbol addSymbolEntry(String name, byte type, byte secHdrIndex, long offset) { 78 // Get the current symbol index and append symbol name to string table. 79 int index; 80 MachOSymbol sym; 81 82 if (name.isEmpty()) { 83 index = 0; 84 strTabContent.append('\0'); 85 strTabNrOfBytes += 1; 86 sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset); 87 localSymbols.add(sym); 88 } else { 89 // We can't trust strTabContent.length() since that is 90 // chars (UTF16), keep track of bytes on our own. 91 index = strTabNrOfBytes; 92 strTabContent.append("_").append(name).append('\0'); 93 // + 1 for null, + 1 for "_" 94 strTabNrOfBytes += (name.getBytes().length + 1 + 1); 95 96 sym = new MachOSymbol(symbolCount, index, type, secHdrIndex, offset); 97 switch (type) { 98 case nlist_64.N_EXT: 99 undefSymbols.add(sym); 100 break; 101 case nlist_64.N_SECT: 102 case nlist_64.N_UNDF: // null symbol 103 localSymbols.add(sym); 104 break; 105 case nlist_64.N_SECT | nlist_64.N_EXT: 106 globalSymbols.add(sym); 107 break; 108 default: 109 System.out.println("Unsupported Symbol type " + type); 110 break; 111 } 112 } 113 symbolCount++; 114 return (sym); 115 } 116 117 void setOffset(int symoff) { 118 symtabCmd.putInt(symtab_command.symoff.off, symoff); 119 } 120 121 // Update the symbol indexes once all symbols have been added. 122 // This is required since we'll be reordering the symbols in the 123 // file to be in the order of Local, global and Undefined. 124 void updateIndexes() { 125 int index = 0; 126 127 // Update the local symbol indexes 128 for (int i = 0; i < localSymbols.size(); i++) { 129 MachOSymbol sym = localSymbols.get(i); 130 sym.setIndex(index++); 131 } 132 133 // Update the global symbol indexes 134 for (int i = 0; i < globalSymbols.size(); i++) { 135 MachOSymbol sym = globalSymbols.get(i); 136 sym.setIndex(index++); 137 } 138 139 // Update the undefined symbol indexes 140 for (int i = index; i < undefSymbols.size(); i++) { 141 MachOSymbol sym = undefSymbols.get(i); 142 sym.setIndex(index++); 143 } 144 } 145 146 // Update LC_SYMTAB command fields based on the number of symbols added 147 // return the file size taken up by symbol table entries and strings 148 int calcSizes() { 149 int stroff; 150 151 stroff = symtabCmd.getInt(symtab_command.symoff.off) + (nlist_64.totalsize * symbolCount); 152 symtabCmd.putInt(symtab_command.nsyms.off, symbolCount); 153 symtabCmd.putInt(symtab_command.stroff.off, stroff); 154 symtabCmd.putInt(symtab_command.strsize.off, strTabNrOfBytes); 155 symtabDataSize = (nlist_64.totalsize * symbolCount) + strTabNrOfBytes; 156 157 return (symtabDataSize); 158 } 159 160 int getNumLocalSyms() { 161 return localSymbols.size(); 162 } 163 164 int getNumGlobalSyms() { 165 return globalSymbols.size(); 166 } 167 168 int getNumUndefSyms() { 169 return undefSymbols.size(); 170 } 171 172 byte[] getCmdArray() { 173 return symtabCmd.array(); 174 } 175 176 // Create a single byte array that contains the symbol table entries 177 // and string table 178 byte[] getDataArray() { 179 ByteBuffer 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 }