1 package com.ochafik.lang.jnaerator.nativesupport;
2
3 import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.IMAGE_DIRECTORY_ENTRY_EXPORT;
4 import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.IMAGE_DOS_SIGNATURE;
5 import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.IMAGE_NT_SIGNATURE;
6 import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.INSTANCE;
7 import static com.ochafik.lang.jnaerator.nativesupport.dllexport.DbgHelpLibrary.UNDNAME_COMPLETE;
8
9 import static com.ochafik.lang.jnaerator.nativesupport.NativeExportUtils.*;
10
11 import java.io.File;
12 import java.io.IOException;
13 import java.io.RandomAccessFile;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.regex.Pattern;
17
18 import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_DOS_HEADER;
19 import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_EXPORT_DIRECTORY;
20 import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_NT_HEADERS;
21 import com.ochafik.lang.jnaerator.nativesupport.dllexport.IMAGE_SECTION_HEADER;
22 import com.ochafik.util.string.RegexUtils;
23 import com.sun.jna.Memory;
24 import com.sun.jna.Pointer;
25 import com.sun.jna.PointerUtils;
26
27 public class DllExport {
28 private static final Pattern libraryFileNamePattern = Pattern.compile("^([^.]+)\\.dll");
29 public static String createSourceFile(File sourceFile, List<ParsedExport> dllExports) {
30 if (dllExports == null)
31 return null;
32
33 StringBuilder b = new StringBuilder();
34 b.append("#line \"" + sourceFile + "\"\n");
35 for (ParsedExport ex : dllExports) {
36 b.append("// @mangling " + ex.mangling + "\n");
37 b.append(ex.demangled + ";\n");
38 b.append("\n");
39 }
40 return b.toString();
41 }
42 public static List<ParsedExport> parseDllExports(File f) throws IOException {
43 List<ParsedExport> ret = new ArrayList<ParsedExport>();
44 List<String> list = OutputDllFunctions(f);
45 if (list == null)
46 return null;
47
48 String library = RegexUtils.findFirst(f.getName(), libraryFileNamePattern, 1);
49
50 int outSize = 8196;
51 byte[] bytes = new byte[outSize];
52 Memory m = new Memory(outSize);
53 for (String symbol : list) {
54 INSTANCE.UnDecorateSymbolName(symbol, m.getByteBuffer(0, outSize), outSize, UNDNAME_COMPLETE);
55 m.read(0, bytes, 0, outSize);
56 int len = 0;
57 while (len < outSize && bytes[len] != 0)
58 len++;
59 ParsedExport ex = new ParsedExport();
60 ex.mangling = symbol;
61 ex.demangled = new String(bytes, 0, len);
62 ex.library = library ;
63 ret.add(ex);
64 }
65 return ret;
66 }
67 private static List<String> OutputDllFunctions(File f) throws IOException {
68 RandomAccessFile raf = new RandomAccessFile(f, "r");
69 IMAGE_DOS_HEADER dosHeader = deserializeStruct(new IMAGE_DOS_HEADER(), raf, 0);
70 if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)
71 return null;
72
73 long ntHeaderBase = dosHeader.e_lfanew.longValue();
74 IMAGE_NT_HEADERS ntHeader = deserializeStruct(new IMAGE_NT_HEADERS(), raf, ntHeaderBase);
75 if (ntHeader.Signature != IMAGE_NT_SIGNATURE)
76 return null;
77
78 int exportsStartRVA = ntHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
79 IMAGE_SECTION_HEADER header = GetExportsSectionHeader(raf, exportsStartRVA, ntHeaderBase, ntHeader );
80 if (header == null)
81 return null;
82
83 int delta = header.VirtualAddress - header.PointerToRawData;
84 IMAGE_EXPORT_DIRECTORY exportDir = deserializeStruct(new IMAGE_EXPORT_DIRECTORY(), raf, exportsStartRVA - delta);
85
86 List<String> ret = new ArrayList<String>(exportDir.NumberOfNames);
87
88
89 for (int i = 0; i < exportDir.NumberOfNames; i++ ) {
90 int pstr = readLittleEndianInt(raf, PointerUtils.getAddress(exportDir.AddressOfNames) - delta + i * Pointer.SIZE);
91 String name = new String(GetFileBytes(raf, pstr - delta, -1));
92 ret.add(name);
93 }
94 return ret;
95 }
96 private static IMAGE_SECTION_HEADER GetExportsSectionHeader(RandomAccessFile raf, int exportsStartRVA, long ntHeaderBase, IMAGE_NT_HEADERS ntHeader) throws IOException {
97 IMAGE_SECTION_HEADER firstSection = new IMAGE_SECTION_HEADER();
98 byte[] bytes = GetFileBytes(
99 raf,
100 ntHeaderBase +
101 PointerUtils.getAddress(ntHeader.OptionalHeader.getPointer()) -
102 PointerUtils.getAddress(ntHeader.getPointer()) +
103 ntHeader.FileHeader.SizeOfOptionalHeader,
104 firstSection.size() * ntHeader.FileHeader.NumberOfSections
105 );
106 IMAGE_SECTION_HEADER[] sections = firstSection.toArray(ntHeader.FileHeader.NumberOfSections);
107 sections[0].getPointer().write(0, bytes, 0, bytes.length);
108 for (IMAGE_SECTION_HEADER section : sections) {
109 section.read();
110 if (exportsStartRVA >= section.VirtualAddress && exportsStartRVA < (section.VirtualAddress + section.Misc.VirtualSize))
111 return section;
112 }
113 return null;
114 }
115 }