1 /* $Header: d:/cvsroot/tads/tads3/vmwrtimg.h,v 1.4 1999/07/11 00:46:59 MJRoberts Exp $ */
2 
3 /*
4  *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
5  *
6  *   Please see the accompanying license file, LICENSE.TXT, for information
7  *   on using and copying this software.
8  */
9 /*
10 Name
11   vmwrtimg.h - T3 Image File Writer utility functions
12 Function
13 
14 Notes
15 
16 Modified
17   04/04/99 MJRoberts  - Creation
18 */
19 
20 #ifndef VMWRTIMG_H
21 #define VMWRTIMG_H
22 
23 #include "t3std.h"
24 #include "vmtype.h"
25 
26 
27 class CVmImageWriter
28 {
29 public:
30     /* create an image writer with a given output file */
31     CVmImageWriter(class CVmFile *fp);
32 
33     /* delete the image writer */
34     ~CVmImageWriter();
35 
36     /* get the current seek location in the underlying file */
37     long get_pos() const;
38 
39     /*
40      *   Prepare the file: write out the fixed header information.  This
41      *   should be called once, before doing any other writing.  'vsn' is
42      *   the image file version number to store in the file.
43      */
44     void prepare(uint vsn, const char tool_data[4]);
45 
46     /*
47      *   Begin a block with the specified ID (a four-byte string).  Writes
48      *   the block header, and remembers where the block starts so that
49      *   the size prefix can be stored when the block is finished.  Blocks
50      *   cannot be nested; starting a new block automatically ends the
51      *   previous block.
52      */
53     void begin_block(const char *block_id, int mandatory);
54 
55     /*
56      *   End the current block.
57      */
58     void end_block();
59 
60     /* write raw bytes to the image file */
61     void write_bytes(const char *ptr, uint32 siz);
62 
63     /*
64      *   Write a complete entrypoint block, given the code offset of the
65      *   entrypoint and the various table entry sizes.  If a block is in
66      *   progress, this will terminate it.
67      */
68     void write_entrypt(uint32 entry_ofs, size_t method_header_size,
69                        size_t exc_entry_size, size_t line_entry_size,
70                        size_t dbg_hdr_size, size_t dbg_lclsym_hdr_size,
71                        int dbg_vsn_id);
72 
73     /*
74      *   Write a complete function set dependency block, given an array of
75      *   function set names.  If a block is in progress, this will
76      *   terminate it.
77      */
78     void write_func_dep(const char **funcset_names, int count);
79 
80     /*
81      *   Write a complete metaclass dependency block, given an array of
82      *   metaclass names.  If a block is in progress, this will terminate
83      *   it.
84      */
85     void write_meta_dep(const char **metaclass_names, int count);
86 
87     /*
88      *   Write a metaclass dependency block in pieces.  Call
89      *   begin_meta_dep() with the number of metaclasses, then call
90      *   write_meta_dep_item() to write each item, and finally call
91      *   end_meta_dep() to finish the block.
92      */
93     void begin_meta_dep(int count);
94     void write_meta_dep_item(const char *metaclass_name);
95     void write_meta_item_prop(uint prop_id);
96     void end_meta_prop_list();
97     void end_meta_dep();
98 
99     /*
100      *   Write a function set dependency block in pieces
101      */
begin_func_dep(int count)102     void begin_func_dep(int count)
103         { begin_dep_block("FNSD", count); }
write_func_dep_item(const char * funcset_name)104     void write_func_dep_item(const char *funcset_name)
105         { write_dep_block_item(funcset_name); }
end_func_dep()106     void end_func_dep()
107         { end_dep_block(); }
108 
109     /*
110      *   Write a constant pool definition block.
111      */
112     void write_pool_def(uint pool_id, uint32 page_count, uint32 page_size,
113                         int mandatory);
114 
115     /*
116      *   Fix up a constant pool definition block with the actual number of
117      *   pages.  This can be used, if desired, to wait to determine the
118      *   actual number of pages in a given constant pool until after
119      *   writing the pages.  Since the pool definition block must precede
120      *   the pool's first page block in the image file, it's impossible to
121      *   wait until after writing all of the pages to write the definition
122      *   block.  Instead, the caller must write the pool definition block
123      *   first, using a temporary placeholder value for the page_count (0
124      *   will suffice), then write the pool pages, then use this to fix up
125      *   the pool definition block with the actual number of pages.  The
126      *   caller must note the seek position prior to writing the pool
127      *   definition block, so that we can seek back to that position to
128      *   fix up the definition block.
129      *
130      *   Callers need not use this function if they know the actual number
131      *   of pages in the pool when writing the original pool definition
132      *   block.
133      */
134     void fix_pool_def(long def_seek_ofs, uint32 page_count);
135 
136     /*
137      *   Write a constant/code pool page.  This writes the entire page
138      *   with its header and data in a single operation; this is the
139      *   easiest way to write a page when the page has been fully
140      *   constructed in a single memory block in advance.
141      */
142     void write_pool_page(uint pool_id, uint32 page_index,
143                          const char *page_data, uint32 page_data_size,
144                          int mandatory, uchar xor_mask);
145 
146     /*
147      *   Write a constant/code pool page in pieces.  These routines can be
148      *   used when the data in the page are not contiguous in memory and
149      *   must be written in pieces.  Start by calling begin_pool_page(),
150      *   then call write_pool_page_bytes() for each item; the items are
151      *   written contiguously to the page.  Finish by calling
152      *   end_pool_page().
153      */
154     void begin_pool_page(uint pool_id, uint32 page_index, int mandatory,
155                          uchar xor_mask);
156     void write_pool_page_bytes(const char *buf, uint32 siz, uchar xor_mask);
157     void end_pool_page();
158 
159     /*
160      *   Write items in the symbolic names block.  Start with
161      *   begin_sym_block(), then call the write_sym_item_xxx() functions
162      *   to write the names.  Finally, call end_sym_block() when done.
163      */
164     void begin_sym_block();
165 
166     void write_sym_item_objid(const char *nm, size_t len, ulong obj_id);
167     void write_sym_item_propid(const char *nm, size_t len, uint prop_id);
168     void write_sym_item_func(const char *nm, size_t len, ulong code_ofs);
169     void write_sym_item(const char *nm, size_t nmlen,
170                         const struct vm_val_t *val);
171 
write_sym_item_objid(const char * nm,ulong obj_id)172     void write_sym_item_objid(const char *nm, ulong obj_id)
173         { write_sym_item_objid(nm, get_strlen(nm), obj_id); }
write_sym_item_propid(const char * nm,uint prop_id)174     void write_sym_item_propid(const char *nm, uint prop_id)
175         { write_sym_item_propid(nm, get_strlen(nm), prop_id); }
write_sym_item(const char * nm,const struct vm_val_t * val)176     void write_sym_item(const char *nm, const struct vm_val_t *val)
177         { write_sym_item(nm, get_strlen(nm), val); }
178 
179     void end_sym_block();
180 
181 
182     /*
183      *   Write items in an OBJS (static object data) block.  Start with
184      *   begin_objs_block(), then call write_objs_bytes() repeatedly to
185      *   write the bytes.  Finally, call end_objs_block() when done.
186      *
187      *   If the 'large_objects' field is set, the objects in the block use
188      *   32-bit size fields; otherwise the objects use 16-bit size fields.
189      *
190      *   If 'trans' is true, the objects in this block are transient;
191      *   otherwise, the objects are non-transient (i.e., persistent).
192      */
193     void begin_objs_block(uint metaclass_idx, int large_objects, int trans);
194     void write_objs_bytes(const char *buf, uint32 siz);
195     void end_objs_block(uint object_count);
196 
197     /*
198      *   Write the items in a SRCF (source file descriptor) block.  Start
199      *   with begin_srcf_block(), then write the file entries.  For each
200      *   entry, call begin_src_entry(), then call write_src_line_entry()
201      *   for each source line debug record, then call end_srcf_entry().
202      *   Call end_srcf_block() when done with all file entries.
203      */
204     void begin_srcf_block(int count);
205     void begin_srcf_entry(int orig_index, const char *fname);
206     void write_srcf_line_entry(ulong linenum, ulong addr);
207     void end_srcf_entry();
208     void end_srcf_block();
209 
210     /*
211      *   Write the items in a GSYM (global symbol table) block.  Start
212      *   with begin_gsym_block(), then call write_gsym_entry() repeatedly
213      *   to write the entries.  Call end_gsym_block() when done.
214      */
215     void begin_gsym_block();
216     void write_gsym_entry(const char *sym, size_t sym_len,
217                           int type_id, const char *dat, size_t dat_len);
218     void end_gsym_block(ulong count);
219 
220     /*
221      *   Begin MHLS block, write an item, and end the block
222      */
223     void begin_mhls_block();
224     void write_mhls_entry(ulong code_addr);
225     void end_mhls_block();
226 
227     /*
228      *   Begin/end SINI block.  static_cs_ofs is the offset in the code
229      *   segment of the first static initializer; this is useful in the
230      *   image file because we can delete all of the code pages starting
231      *   at this point after pre-initialization is complete.
232      */
233     void begin_sini_block(ulong static_cs_ofs, ulong init_cnt);
234     void end_sini_block();
235 
236     /* begin/end a MACR (macro symbols) block */
237     void begin_macr_block();
238     void end_macr_block();
239 
240     /*
241      *   Finish the file.  Automatically ends the current block if a block
242      *   is open, and writes the end-of-file marker.
243      */
244     void finish();
245 
246     /*
247      *   get the underlying file object; for some types of blocks, it's
248      *   simplest for the caller to write the data directly to the underlying
249      *   file stream without any help from us
250      */
get_fp()251     class CVmFile *get_fp() const { return fp_; }
252 
253 private:
254     /* write a generic dependency (function set, metaclass) block */
255     void write_dep_block(const char *block_id, const char **names, int count);
256 
257     /* write a dependency block in pieces */
258     void begin_dep_block(const char *block_id, int count);
259     void write_dep_block_item(const char *nm);
260     void end_dep_block();
261 
262     /* XOR a block of bytes with a mask and write the results to the file */
263     void xor_and_write_bytes(const char *p, uint32 len, uchar xor_mask);
264 
265     /* underlying file */
266     class CVmFile *fp_;
267 
268     /*
269      *   Seek position of start of current block.  If this is zero, no
270      *   block is currently open.
271      */
272     long block_start_;
273 
274     /* count of symbolic names written so far (for writing SYMD block) */
275     int symd_cnt_;
276 
277     /* location of metaclass entry next-record offset */
278     long mcld_ofs_pos_;
279 
280     /* location of metaclass property list count prefix */
281     long mcld_propcnt_pos_;
282 
283     /* count of properties writeen in a metaclass prop list so far */
284     int mcld_prop_cnt_;
285 
286     /* seek location of SYMD count prefix, for fixing up at end of block */
287     long symd_prefix_;
288 
289     /* seek location of OBJS count prefix, for fixup up at end of block */
290     long objs_prefix_;
291 
292     /* seek location of GSYM count prefix, for fixup at end of block */
293     long gsym_prefix_;
294 
295     /* start of current SRCF file entry */
296     long srcf_entry_pos_;
297 
298     /* count of SRCF line entries */
299     long srcf_line_cnt_;
300 
301     /* position of SRCF line entry for the current file */
302     long srcf_line_pos_;
303 
304     /* position of MHLS block count entry, and MHLS entry count so far */
305     long mhls_cnt_pos_;
306     ulong mhls_cnt_;
307 };
308 
309 #endif /* VMWRTIMG_H */
310 
311