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