2 * DLL symbol extraction
4 * Copyright 2000 Jon Griffiths
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)
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 /*******************************************************************
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
;
62 dll_file
= open_file (dll_name
, ".dll", "r");
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");
91 printf ("DLL has %d sections\n", count
);
93 /* Iterate through sections until we find exports */
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
)
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");
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");
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' */
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
]);
157 printf ("%d exported symbols in DLL\n", dll_num_exports
);
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 /*******************************************************************
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
)
183 assert (dll_symbols
);
184 assert (dll_symbols
[current_export
]);
186 return strdup (dll_symbols
[current_export
++]);
190 /*******************************************************************
193 * Free resources used by DLL
195 static void dll_close (void)
207 for (i
= 0; i
< dll_num_exports
; i
++)
209 free (dll_symbols
[i
]);