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.pecoff;
  25 
  26 import java.nio.ByteBuffer;
  27 import java.nio.ByteOrder;
  28 import java.util.ArrayList;
  29 
  30 import jdk.tools.jaotc.binformat.pecoff.PECoff;
  31 import jdk.tools.jaotc.binformat.pecoff.PECoff.IMAGE_SYMBOL;
  32 import jdk.tools.jaotc.binformat.pecoff.PECoffSymbol;
  33 import jdk.tools.jaotc.binformat.pecoff.PECoffByteBuffer;
  34 
  35 public class PECoffSymtab {
  36     ArrayList<PECoffSymbol>symbols = new ArrayList<PECoffSymbol>();
  37 
  38     /**
  39      * number of symbols added
  40      */
  41     int symbolCount;
  42 
  43     /**
  44      * String holding symbol table strings
  45      */
  46     private StringBuilder strTabContent;
  47 
  48     /**
  49      * Keeps track of bytes in string table since strTabContent.length()
  50      * is number of chars, not bytes.
  51      */
  52     private int strTabNrOfBytes;
  53 
  54     /**
  55      * String holding Linker Directives
  56      */
  57     private StringBuilder directives;
  58 
  59     public PECoffSymtab() {
  60         symbolCount = 0;
  61         strTabContent = new StringBuilder();
  62         directives = new StringBuilder();
  63 
  64         // The first 4 bytes of the string table contain
  65         // the length of the table (including this length field).
  66         strTabNrOfBytes = 4;
  67 
  68         // Make room for the 4 byte length field
  69         strTabContent.append('\0').append('\0').append('\0').append('\0');
  70 
  71         // Linker Directives start with 3 spaces to signify ANSI
  72         directives.append("   ");
  73     }
  74 
  75     public PECoffSymbol addSymbolEntry(String name, byte type, byte storageclass,
  76                                     byte secHdrIndex, long offset, long size) {
  77         // Get the current symbol index and append symbol name to string table.
  78         int index;
  79         PECoffSymbol sym;
  80 
  81         if (name.isEmpty()) {
  82             index = 0;
  83             strTabContent.append('\0');
  84             strTabNrOfBytes += 1;
  85             sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
  86             symbols.add(sym);
  87         } else {
  88             int nameSize = name.getBytes().length;
  89 
  90             // We can't trust strTabContent.length() since that is
  91             // chars (UTF16), keep track of bytes on our own.
  92             index = strTabNrOfBytes;
  93             // strTabContent.append('_').append(name).append('\0');
  94             strTabContent.append(name).append('\0');
  95             strTabNrOfBytes += (nameSize + 1);
  96 
  97             sym = new PECoffSymbol(symbolCount, index, type, storageclass, secHdrIndex, offset, size);
  98             symbols.add(sym);
  99             if (storageclass == IMAGE_SYMBOL.IMAGE_SYM_CLASS_EXTERNAL)
 100                 addDirective(name, type);
 101         }
 102         symbolCount++;
 103         return (sym);
 104     }
 105 
 106     private void addDirective(String name, byte type) {
 107         directives.append("/EXPORT:" + name);
 108         if(type != IMAGE_SYMBOL.IMAGE_SYM_DTYPE_FUNCTION) {
 109             directives.append(",DATA");
 110         }
 111         directives.append(" ");
 112     }
 113 
 114     public int getSymtabCount() {
 115         return symbolCount;
 116     }
 117 
 118     public int getStrtabSize() {
 119         return strTabNrOfBytes;
 120     }
 121 
 122     // Return a byte array that contains the symbol table entries
 123     public byte[] getSymtabArray() {
 124         ByteBuffer symtabData = PECoffByteBuffer.allocate(symbolCount*IMAGE_SYMBOL.totalsize);
 125         symtabData.order(ByteOrder.LITTLE_ENDIAN);
 126 
 127         // copy all symbols
 128         for (int i = 0; i < symbolCount; i++ ) {
 129             PECoffSymbol sym = symbols.get(i);
 130             byte [] arr = sym.getArray();
 131             symtabData.put(arr);
 132         }
 133         return (symtabData.array());
 134     }
 135 
 136     // Return the string table array
 137     public byte[] getStrtabArray() {
 138         byte [] strs = strTabContent.toString().getBytes();
 139 
 140         // Update the size of the string table
 141         ByteBuffer buff = ByteBuffer.wrap(strs);
 142         buff.order(ByteOrder.LITTLE_ENDIAN);
 143         buff.putInt(0, strTabNrOfBytes);
 144 
 145         return (strs);
 146     }
 147 
 148     public byte[] getDirectiveArray() {
 149         return (directives.toString().getBytes());
 150     }
 151 }