1 /*
2  *	HT Editor
3  *	out_sym.cc
4  *
5  *	Copyright (C) 1999-2002 Sebastian Biallas (sb@biallas.net)
6  *	Copyright (C) 2002 Stefan Weyergraf
7  *
8  *	This program is free software; you can redistribute it and/or modify
9  *	it under the terms of the GNU General Public License version 2 as
10  *	published by the Free Software Foundation.
11  *
12  *	This program is distributed in the hope that it will be useful,
13  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *	GNU General Public License for more details.
16  *
17  *	You should have received a copy of the GNU General Public License
18  *	along with this program; if not, write to the Free Software
19  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 #include "analy_names.h"
23 #include "htdebug.h"
24 #include "htinfo.h"
25 #include "out_html.h"
26 #include "tools.h"
27 #include "x86dis.h"
28 #include "string.h"
29 
30 /*
31  *
32  *	Format of .SYM files:
33  * ==========================================================================
34  *	1. Header, see (1)
35  *	2. "seg_count" "Segment tables", see (2)
36  *	3. Terminator ???, see (A)
37  *
38  *   (1) Header
39  * ==========================================================================
40  *	The header holds the number of symbols+something ('q_count'),
41  *	the number of segments ('seg_count') and the module_name.
42  *	I dont know what the other fields stand for...
43  *	The header always has 32 bytes.
44  *
45  *	(2) Segment table (starts 16-byte aligned)
46  * ==========================================================================
47  *	(2.1) Segment Header
48  *	- number of symbols "n"
49  *	- pointer to "Symbol pointer table" see (2.3), relative to start of
50  *	  this header
51  *
52  *	(2.2) Symbol table
53  *	- usually has "n+1" entries of "Symbol table entry", see (3)
54  *	- first entry usually is segment descriptor (informative)
55  *
56  *	(2.3) Symbol pointer table
57  *	- consists of "n" entries of 16-bit pointers to a "Symbol table entry"
58  *	  (pointers are relative to "Segment Header")
59  *
60  *   (3) Symbol table entry
61  * ==========================================================================
62  *	contains 32-bit integer ("the address"), followed by a counted
63  *	(Pascal-style) string ("the name").
64  *
65  *   (A) Appendix A - Unsure
66  * ==========================================================================
67  *	observed files always had an additional 4 bytes appended.
68  *	bytes are either 00,00,00,04 or 00,00,00,06
69  */
70 
71 struct ImageSymHeader {
72 	uint32 file_size;		// in 16-byte blocks
73 	uint16 entry_seg;
74 	uint16 u0;				// 0000
75 	uint16 u1;				// 0015 (some flags ?, 0014 for 16-bit .SYM ?)
76 	uint16 seg_count;
77 	uint32 u2;				// 04020002 (some flags ?)
78 	byte	module_name[16];
79 } PACKED;
80 
81 struct ImageSymSegHeader {
82 	uint16 next_rec_ofs;		// in 16-byte blocks (ring list, last points to first)
83 	uint16 sym_count;
84 	uint16 sym_ptr_table_ptr;
85 	uint16 seg_idx;
86 	uint32 seg_start;
87 	uint32 seg_size;
88 } PACKED;
89 
90 struct ImageSymDescriptor {
91 	uint32 address;
92 //	byte  name_len;
93 //   name;
94 //   ^^^^ pascal string
95 } PACKED;
96 
97 /*
98  *
99  */
100 
101 #define MAX_BYTES_PER_SEGMENT		0xff00
102 #define MAX_SYMBOLS_PER_SEGMENT		0x4000
103 
write_sym(Stream & stream,uint32 addr,const char * name,uint * bytes_written)104 static void write_sym(Stream &stream, uint32 addr, const char *name, uint *bytes_written)
105 {
106 	ImageSymDescriptor desc;
107 	desc.address = addr;
108 	stream.write(&desc, sizeof desc); // FIXME: endianess !
109 	stream.writestrp(name);
110 	*bytes_written += sizeof desc + 1 + strlen(name);
111 }
112 
g(Stream & stream,Symbol * s,uint * bytes_written,uint * symbols_written,uint16 * ptr_table)113 static void g(Stream &stream, Symbol *s, uint *bytes_written, uint *symbols_written, uint16 *ptr_table)
114 {
115 	if (*bytes_written >= MAX_BYTES_PER_SEGMENT) return;
116 	if (*symbols_written >= MAX_SYMBOLS_PER_SEGMENT) return;
117 
118 	uint32 addr;
119 	if (s->location->addr->byteSize() == sizeof addr) {
120 		s->location->addr->putIntoArray((byte*)&addr);
121 //		addr -= 0xbff70000;	/* FIXME: hack for kernel32.dll */
122 	} else {
123 		addr = 0;
124 	}
125 
126 	ptr_table[*symbols_written] = *bytes_written;
127 	write_sym(stream, addr, s->name, bytes_written);
128 
129 	(*symbols_written) ++;
130 }
131 
align16(File * file,uint * bytes_written)132 static void align16(File *file, uint *bytes_written)
133 {
134 	byte c = 0;
135 	while (*bytes_written % 16) {
136 		file->write(&c, 1);
137 		(*bytes_written) ++;
138 	}
139 }
140 
export_to_sym(Analyser * analy,File * file)141 int export_to_sym(Analyser *analy, File *file)
142 {
143 	if ((!analy) || (!file)) return /*HTML_OUTPUT_ERR_GENERIC*/1;
144 	if (analy->active) return /*HTML_OUTPUT_ERR_ANALY_NOT_FINISHED*/1;
145 
146 	const char *module_name = "TEST";
147 	ImageSymHeader head;
148 	ImageSymSegHeader seg_head;
149 
150 // write dummy header
151 	memset(&head, 0, sizeof head);
152 	file->write(&head, sizeof head);
153 
154 
155 /* foreach ($seg) { */
156 
157 // write dummy seg header
158 	memset(&seg_head, 0, sizeof seg_head);
159 	file->write(&seg_head, sizeof seg_head);
160 
161 	uint bytes_written = sizeof seg_head, symbols_written = 0;
162 
163 	write_sym(*file, 0xff000000, "_TEXT", &bytes_written);
164 
165 	uint16 *ptr_table = ht_malloc(MAX_SYMBOLS_PER_SEGMENT * sizeof *ptr_table);
166 
167 	Symbol *sym = NULL;
168 	while ((sym = analy->enumSymbols(sym))) {
169 		g(*file, sym, &bytes_written, &symbols_written, ptr_table);
170 	}
171 
172 	uint sym_ptr_table_ptr = bytes_written;
173 
174 	// FIXME: endianess !
175 	file->write(ptr_table, sizeof *ptr_table * symbols_written);
176 	bytes_written += sizeof *ptr_table * symbols_written;
177 	free(ptr_table);
178 
179 	align16(file, &bytes_written);
180 
181 	// FIXME: wrong code order, endianess !
182 	uint32 terminator = 0x04000000;
183 	file->write(&terminator, sizeof terminator);
184 	bytes_written += 4;
185 
186 	file->seek(0x0020);
187 // write segment header
188 	seg_head.next_rec_ofs = 0x0002;
189 	seg_head.sym_count = symbols_written;
190 	seg_head.sym_ptr_table_ptr = sym_ptr_table_ptr;
191 	seg_head.seg_idx = 1;
192 	seg_head.seg_start = 0;
193 	seg_head.seg_size = 0x0000ffff;
194 	// FIXME: endianess !
195 	file->write(&seg_head, sizeof seg_head);
196 
197 /* } */
198 
199 
200 	bytes_written += sizeof head;
201 	file->seek(0);
202 // write header
203 	head.file_size = (bytes_written-1) / 16;
204 	head.entry_seg = 0;
205 	head.u0 = 0;
206 	head.u1 = 0x0015;
207 	head.seg_count = 1;
208 	head.u2 = 0x04020002;
209 	memcpy(head.module_name, module_name, MIN(strlen(module_name), sizeof head.module_name));
210 	// FIXME: endianess !
211 	file->write(&head, sizeof head);
212 
213 	return 0;
214 }
215 
216