Added spec generation tool specmaker.
[wine.git] / tools / specmaker / dll.c
blob52ef299c2ce0ebaf716861d1b6ca9f5fefb73cb1
1 /*
2 * DLL symbol extraction
4 * Copyright 2000 Jon Griffiths
5 */
6 #include "specmaker.h"
8 /* DOS/PE Header details */
9 #define DOS_HEADER_LEN 64
10 #define DOS_MAGIC 0x5a4d
11 #define DOS_PE_OFFSET 60
12 #define PE_HEADER_LEN 248
13 #define PE_MAGIC 0x4550
14 #define PE_COUNT_OFFSET 6
15 #define PE_EXPORTS_OFFSET 120
16 #define PE_EXPORTS_SIZE PE_EXPORTS_OFFSET + 4
17 #define SECTION_HEADER_LEN 40
18 #define SECTION_ADDR_OFFSET 12
19 #define SECTION_ADDR_SIZE SECTION_ADDR_OFFSET + 4
20 #define SECTION_POS_OFFSET SECTION_ADDR_SIZE + 4
21 #define EXPORT_COUNT_OFFSET 24
22 #define EXPORT_NAME_OFFSET EXPORT_COUNT_OFFSET + 8
24 /* Minimum memory needed to read both headers into a buffer */
25 #define MIN_HEADER_LEN (PE_HEADER_LEN * sizeof (unsigned char))
27 /* Normalise a pointer in the exports section */
28 #define REBASE(x) ((x) - exports)
30 /* Module globals */
31 static FILE *dll_file = NULL;
32 static char **dll_symbols = NULL;
33 static size_t dll_num_exports = 0;
36 /* Get a short from a memory block */
37 static inline size_t get_short (const char *mem)
39 return *((const unsigned char *)mem) +
40 (*((const unsigned char *)mem + 1) << 8);
43 /* Get an integer from a memory block */
44 static inline size_t get_int (const char *mem)
46 assert (sizeof (char) == (size_t)1);
47 return get_short (mem) + (get_short (mem + 2) << 16);
50 static void dll_close (void);
53 /*******************************************************************
54 * dll_open
56 * Open a DLL and read in exported symbols
58 void dll_open (const char *dll_name)
60 size_t code = 0, code_len = 0, exports, exports_len, count, symbol_data;
61 char *buff = NULL;
62 dll_file = open_file (dll_name, ".dll", "r");
64 atexit (dll_close);
66 /* Read in the required DOS and PE Headers */
67 if (!(buff = (char *) malloc (MIN_HEADER_LEN)))
68 fatal ("Out of memory");
70 if (fread (buff, DOS_HEADER_LEN, 1, dll_file) != 1 ||
71 get_short (buff) != DOS_MAGIC)
72 fatal ("Error reading DOS header");
74 if (fseek (dll_file, get_int (buff + DOS_PE_OFFSET), SEEK_SET) == -1)
75 fatal ("Error seeking PE header");
77 if (fread (buff, PE_HEADER_LEN, 1, dll_file) != 1 ||
78 get_int (buff) != PE_MAGIC)
79 fatal ("Error reading PE header");
81 exports = get_int (buff + PE_EXPORTS_OFFSET);
82 exports_len = get_int (buff + PE_EXPORTS_SIZE);
84 if (!exports || !exports_len)
85 fatal ("No exports in DLL");
87 if (!(count = get_short (buff + PE_COUNT_OFFSET)))
88 fatal ("No sections in DLL");
90 if (VERBOSE)
91 printf ("DLL has %d sections\n", count);
93 /* Iterate through sections until we find exports */
94 while (count--)
96 if (fread (buff, SECTION_HEADER_LEN, 1, dll_file) != 1)
97 fatal ("Section read error");
99 code = get_int (buff + SECTION_ADDR_OFFSET);
100 code_len = get_int (buff + SECTION_ADDR_SIZE);
102 if (code <= exports && code + code_len > exports)
103 break;
106 if (!count)
107 fatal ("No export section");
109 code_len -= (exports - code);
111 if (code_len < exports_len)
112 fatal ("Corrupt exports");
114 /* Load exports section */
115 if (fseek (dll_file, get_int (buff + SECTION_POS_OFFSET)
116 + exports - code, SEEK_SET) == -1)
117 fatal ("Export section seek error");
119 if (VERBOSE)
120 printf ("Export data size = %d bytes\n", code_len);
122 if (!(buff = (char *) realloc (buff, code_len)))
123 fatal ("Out of memory");
125 if (fread (buff, code_len, 1, dll_file) != 1)
126 fatal ("Read error");
128 dll_close();
130 /* Locate symbol names */
131 symbol_data = REBASE( get_int (buff + EXPORT_NAME_OFFSET));
133 if (symbol_data > code_len)
134 fatal ("Corrupt exports section");
136 if (!(dll_num_exports = get_int (buff + EXPORT_COUNT_OFFSET)))
137 fatal ("No export count");
139 if (!(dll_symbols = (char **) malloc (dll_num_exports * sizeof (char *))))
140 fatal ("Out of memory");
142 /* Read symbol names into 'dll_symbols' */
143 count = 0;
144 while (count < dll_num_exports)
146 const int symbol_offset = get_int (buff + symbol_data + count * 4);
147 const char *symbol_name_ptr = REBASE (buff + symbol_offset);
149 assert(symbol_name_ptr);
150 dll_symbols[count] = strdup (symbol_name_ptr);
151 assert(dll_symbols[count]);
153 count++;
156 if (NORMAL)
157 printf ("%d exported symbols in DLL\n", dll_num_exports);
159 free (buff);
161 /* Set DLL output names */
162 if ((buff = strrchr (globals.input_name, '/')))
163 globals.input_name = buff + 1; /* Strip path */
165 OUTPUT_UC_DLL_NAME = str_toupper( strdup (OUTPUT_DLL_NAME));
169 /*******************************************************************
170 * dll_next_symbol
172 * Get next exported symbol from dll
174 char* dll_next_symbol ()
176 static unsigned int current_export = 0;
178 assert (current_export <= dll_num_exports);
180 if (current_export == dll_num_exports)
181 return NULL;
183 assert (dll_symbols);
184 assert (dll_symbols [current_export]);
186 return strdup (dll_symbols [current_export++]);
190 /*******************************************************************
191 * dll_close
193 * Free resources used by DLL
195 static void dll_close (void)
197 size_t i;
199 if (dll_file)
201 fclose (dll_file);
202 dll_file = NULL;
205 if (dll_symbols)
207 for (i = 0; i < dll_num_exports; i++)
208 if (dll_symbols [i])
209 free (dll_symbols [i]);
210 free (dll_symbols);
211 dll_symbols = NULL;