blob: a127d34ef8dcf85ccf78a05a095b81e8e0135ac7 [file] [log] [blame]
sewardj35421a32004-07-05 13:12:34 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (main/vex_main.c) is ---*/
sewardj35421a32004-07-05 13:12:34 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
13 Copyright (C) 2004 OpenWorks, LLP.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
35
sewardj887a11a2004-07-05 17:26:47 +000036#include "libvex.h"
sewardj81ec4182004-10-25 23:15:52 +000037#include "libvex_guest_x86.h"
sewardjf13a16a2004-07-05 17:10:14 +000038
sewardjc0ee2ed2004-07-27 10:29:41 +000039#include "main/vex_globals.h"
40#include "main/vex_util.h"
41#include "host-generic/h_generic_regs.h"
42#include "host-x86/hdefs.h"
43#include "guest-x86/gdefs.h"
sewardjedf4d692004-08-17 13:52:58 +000044#include "ir/iropt.h"
sewardj35421a32004-07-05 13:12:34 +000045
46
47/* This file contains the top level interface to the library. */
48
49/* --------- Initialise the library. --------- */
50
51/* Exported to library client. */
52
sewardj08613742004-10-25 13:01:45 +000053void LibVEX_default_VexControl ( /*OUT*/ VexControl* vcon )
54{
55 vcon->iropt_verbosity = 0;
56 vcon->iropt_level = 2;
57 vcon->iropt_precise_memory_exns = False;
58 vcon->iropt_unroll_thresh = 120;
59 vcon->guest_max_insns = 50;
60 vcon->guest_chase_thresh = 10;
61}
62
63
64/* Exported to library client. */
65
sewardj887a11a2004-07-05 17:26:47 +000066void LibVEX_Init (
sewardj35421a32004-07-05 13:12:34 +000067 /* failure exit function */
sewardj2b515872004-07-05 20:50:45 +000068 __attribute__ ((noreturn))
sewardj35421a32004-07-05 13:12:34 +000069 void (*failure_exit) ( void ),
70 /* logging output function */
71 void (*log_bytes) ( Char*, Int nbytes ),
72 /* debug paranoia level */
73 Int debuglevel,
sewardj35421a32004-07-05 13:12:34 +000074 /* Are we supporting valgrind checking? */
75 Bool valgrind_support,
sewardj08613742004-10-25 13:01:45 +000076 /* Control ... */
77 /*READONLY*/VexControl* vcon
sewardj35421a32004-07-05 13:12:34 +000078)
79{
sewardj08613742004-10-25 13:01:45 +000080 /* First off, do enough minimal setup so that the following
81 assertions can fail in a sane fashion, if need be. */
sewardjea602bc2004-10-14 21:40:12 +000082 vex_failure_exit = failure_exit;
83 vex_log_bytes = log_bytes;
84
85 /* Now it's safe to check parameters for sanity. */
sewardj35421a32004-07-05 13:12:34 +000086 vassert(!vex_initdone);
87 vassert(failure_exit);
sewardj35421a32004-07-05 13:12:34 +000088 vassert(log_bytes);
sewardj35421a32004-07-05 13:12:34 +000089 vassert(debuglevel >= 0);
sewardj08613742004-10-25 13:01:45 +000090
91 vassert(vcon->iropt_verbosity >= 0);
92 vassert(vcon->iropt_level >= 0);
93 vassert(vcon->iropt_level <= 2);
94 vassert(vcon->iropt_unroll_thresh >= 0);
95 vassert(vcon->iropt_unroll_thresh <= 400);
96 vassert(vcon->guest_max_insns >= 1);
97 vassert(vcon->guest_max_insns <= 100);
98 vassert(vcon->guest_chase_thresh >= 0);
99 vassert(vcon->guest_chase_thresh < vcon->guest_max_insns);
sewardj443cd9d2004-07-18 23:06:45 +0000100
sewardj81ec4182004-10-25 23:15:52 +0000101 /* All the guest state structs must have an 8-aligned size. */
102 vassert(0 == sizeof(VexGuestX86State) % 8);
103
sewardjea602bc2004-10-14 21:40:12 +0000104 /* Check that Vex has been built with sizes of basic types as
105 stated in priv/libvex_basictypes.h. Failure of any of these is
106 a serious configuration error and should be corrected
107 immediately. If any of these assertions fail you can fully
108 expect Vex not to work properly, if at all. */
109
110 vassert(1 == sizeof(UChar));
111 vassert(1 == sizeof(Char));
112 vassert(2 == sizeof(UShort));
113 vassert(2 == sizeof(Short));
114 vassert(4 == sizeof(UInt));
115 vassert(4 == sizeof(Int));
116 vassert(8 == sizeof(ULong));
117 vassert(8 == sizeof(Long));
118 vassert(4 == sizeof(Float));
119 vassert(8 == sizeof(Double));
120 vassert(1 == sizeof(Bool));
121 vassert(4 == sizeof(Addr32));
122 vassert(8 == sizeof(Addr64));
123
124 vassert(sizeof(void*) == 4 || sizeof(void*) == 8);
125 vassert(sizeof(void*) == sizeof(int*));
126 vassert(sizeof(void*) == sizeof(HWord));
127
128 /* Really start up .. */
sewardj443cd9d2004-07-18 23:06:45 +0000129 vex_debuglevel = debuglevel;
sewardj443cd9d2004-07-18 23:06:45 +0000130 vex_valgrind_support = valgrind_support;
sewardj08613742004-10-25 13:01:45 +0000131 vex_control = *vcon;
sewardj443cd9d2004-07-18 23:06:45 +0000132 vex_initdone = True;
133 LibVEX_SetAllocMode ( AllocModeTEMPORARY );
sewardj35421a32004-07-05 13:12:34 +0000134}
135
136
137/* --------- Make a translation. --------- */
138
139/* Exported to library client. */
140
sewardj887a11a2004-07-05 17:26:47 +0000141TranslateResult LibVEX_Translate (
sewardj35421a32004-07-05 13:12:34 +0000142 /* The instruction sets we are translating from and to. */
143 InsnSet iset_guest,
144 InsnSet iset_host,
145 /* IN: the block to translate, and its guest address. */
sewardj81bd5502004-07-21 18:49:27 +0000146 UChar* guest_bytes,
sewardj35421a32004-07-05 13:12:34 +0000147 Addr64 guest_bytes_addr,
sewardj5bd4d162004-11-10 13:02:48 +0000148 Bool (*chase_into_ok) ( Addr64 ),
sewardj35421a32004-07-05 13:12:34 +0000149 /* OUT: the number of bytes actually read */
150 Int* guest_bytes_read,
151 /* IN: a place to put the resulting code, and its size */
sewardj81bd5502004-07-21 18:49:27 +0000152 UChar* host_bytes,
153 Int host_bytes_size,
sewardj35421a32004-07-05 13:12:34 +0000154 /* OUT: how much of the output area is used. */
155 Int* host_bytes_used,
sewardj49651f42004-10-28 22:11:04 +0000156 /* IN: optionally, two instrumentation functions. */
sewardjcf787902004-11-03 09:08:33 +0000157 IRBB* (*instrument1) ( IRBB*, VexGuestLayout*, IRType hWordTy ),
158 IRBB* (*instrument2) ( IRBB*, VexGuestLayout*, IRType hWordTy ),
sewardj9578a8b2004-11-04 19:44:48 +0000159 Bool cleanup_after_instrumentation,
sewardj35421a32004-07-05 13:12:34 +0000160 /* IN: optionally, an access check function for guest code. */
sewardj58800ff2004-07-28 01:51:10 +0000161 Bool (*byte_accessible) ( Addr64 ),
sewardjf48ac192004-10-29 00:41:29 +0000162 /* IN: debug: trace vex activity at various points */
163 Int traceflags
sewardj35421a32004-07-05 13:12:34 +0000164)
165{
sewardj81bd5502004-07-21 18:49:27 +0000166 /* This the bundle of functions we need to do the back-end stuff
167 (insn selection, reg-alloc, assembly) whilst being insulated
168 from the target instruction set. */
sewardjf13a16a2004-07-05 17:10:14 +0000169 HReg* available_real_regs;
170 Int n_available_real_regs;
sewardj443cd9d2004-07-18 23:06:45 +0000171 Bool (*isMove) (HInstr*, HReg*, HReg*);
172 void (*getRegUsage) (HRegUsage*, HInstr*);
173 void (*mapRegs) (HRegRemap*, HInstr*);
174 HInstr* (*genSpill) ( HReg, Int );
175 HInstr* (*genReload) ( HReg, Int );
176 void (*ppInstr) ( HInstr* );
177 void (*ppReg) ( HReg );
sewardj8ea867b2004-10-30 19:03:02 +0000178 HInstrArray* (*iselBB) ( IRBB* );
sewardj443cd9d2004-07-18 23:06:45 +0000179 IRBB* (*bbToIR) ( UChar*, Addr64, Int*,
sewardj5bd4d162004-11-10 13:02:48 +0000180 Bool(*)(Addr64),
181 Bool(*)(Addr64), Bool );
sewardj81bd5502004-07-21 18:49:27 +0000182 Int (*emit) ( UChar*, Int, HInstr* );
sewardj84ff0652004-08-23 16:16:08 +0000183 IRExpr* (*specHelper) ( Char*, IRExpr** );
sewardj8d2291c2004-10-25 14:50:21 +0000184 Bool (*preciseMemExnsFn) ( Int, Int );
sewardjf13a16a2004-07-05 17:10:14 +0000185
sewardjeeac8412004-11-02 00:26:55 +0000186 VexGuestLayout* guest_layout;
187 Bool host_is_bigendian = False;
188 IRBB* irbb;
189 HInstrArray* vcode;
190 HInstrArray* rcode;
191 Int i, j, k, out_used, guest_sizeB;
192 UChar insn_bytes[32];
sewardjcf787902004-11-03 09:08:33 +0000193 IRType guest_word_type;
194 IRType host_word_type;
sewardjf13a16a2004-07-05 17:10:14 +0000195
sewardj49651f42004-10-28 22:11:04 +0000196 guest_layout = NULL;
sewardj36ca5132004-07-24 13:12:23 +0000197 available_real_regs = NULL;
198 n_available_real_regs = 0;
199 isMove = NULL;
200 getRegUsage = NULL;
201 mapRegs = NULL;
202 genSpill = NULL;
203 genReload = NULL;
204 ppInstr = NULL;
205 ppReg = NULL;
206 iselBB = NULL;
207 bbToIR = NULL;
208 emit = NULL;
sewardj84ff0652004-08-23 16:16:08 +0000209 specHelper = NULL;
sewardj8d2291c2004-10-25 14:50:21 +0000210 preciseMemExnsFn = NULL;
sewardjcf787902004-11-03 09:08:33 +0000211 guest_word_type = Ity_INVALID;
212 host_word_type = Ity_INVALID;
sewardj36ca5132004-07-24 13:12:23 +0000213
sewardjf48ac192004-10-29 00:41:29 +0000214 vex_traceflags = traceflags;
sewardj58800ff2004-07-28 01:51:10 +0000215
sewardj35421a32004-07-05 13:12:34 +0000216 vassert(vex_initdone);
sewardj443cd9d2004-07-18 23:06:45 +0000217 LibVEX_ClearTemporary(False);
sewardjf13a16a2004-07-05 17:10:14 +0000218
219 /* First off, check that the guest and host insn sets
220 are supported. */
221 switch (iset_host) {
222 case InsnSetX86:
223 getAllocableRegs_X86 ( &n_available_real_regs,
224 &available_real_regs );
225 isMove = (Bool(*)(HInstr*,HReg*,HReg*)) isMove_X86Instr;
226 getRegUsage = (void(*)(HRegUsage*,HInstr*)) getRegUsage_X86Instr;
227 mapRegs = (void(*)(HRegRemap*,HInstr*)) mapRegs_X86Instr;
228 genSpill = (HInstr*(*)(HReg,Int)) genSpill_X86;
229 genReload = (HInstr*(*)(HReg,Int)) genReload_X86;
sewardj2b515872004-07-05 20:50:45 +0000230 ppInstr = (void(*)(HInstr*)) ppX86Instr;
231 ppReg = (void(*)(HReg)) ppHRegX86;
sewardjf13a16a2004-07-05 17:10:14 +0000232 iselBB = iselBB_X86;
sewardj81bd5502004-07-21 18:49:27 +0000233 emit = (Int(*)(UChar*,Int,HInstr*)) emit_X86Instr;
sewardjc9a65702004-07-07 16:32:57 +0000234 host_is_bigendian = False;
sewardjcf787902004-11-03 09:08:33 +0000235 host_word_type = Ity_I32;
sewardjf13a16a2004-07-05 17:10:14 +0000236 break;
237 default:
sewardj887a11a2004-07-05 17:26:47 +0000238 vpanic("LibVEX_Translate: unsupported target insn set");
sewardjf13a16a2004-07-05 17:10:14 +0000239 }
240
241 switch (iset_guest) {
242 case InsnSetX86:
sewardj8d2291c2004-10-25 14:50:21 +0000243 preciseMemExnsFn = guest_x86_state_requires_precise_mem_exns;
244 bbToIR = bbToIR_X86Instr;
sewardj8d2291c2004-10-25 14:50:21 +0000245 specHelper = x86guest_spechelper;
sewardj81ec4182004-10-25 23:15:52 +0000246 guest_sizeB = sizeof(VexGuestX86State);
sewardjcf787902004-11-03 09:08:33 +0000247 guest_word_type = Ity_I32;
sewardj49651f42004-10-28 22:11:04 +0000248 guest_layout = &x86guest_layout;
sewardjf13a16a2004-07-05 17:10:14 +0000249 break;
250 default:
sewardj887a11a2004-07-05 17:26:47 +0000251 vpanic("LibVEX_Translate: unsupported guest insn set");
sewardjf13a16a2004-07-05 17:10:14 +0000252 }
253
sewardjf48ac192004-10-29 00:41:29 +0000254 if (vex_traceflags & VEX_TRACE_FE)
255 vex_printf("\n------------------------"
256 " Front end "
257 "------------------------\n\n");
258
sewardjf13a16a2004-07-05 17:10:14 +0000259 irbb = bbToIR ( guest_bytes,
260 guest_bytes_addr,
261 guest_bytes_read,
sewardjc9a65702004-07-07 16:32:57 +0000262 byte_accessible,
sewardj5bd4d162004-11-10 13:02:48 +0000263 chase_into_ok,
sewardjc9a65702004-07-07 16:32:57 +0000264 host_is_bigendian );
sewardjf13a16a2004-07-05 17:10:14 +0000265
266 if (irbb == NULL) {
267 /* Access failure. */
sewardj443cd9d2004-07-18 23:06:45 +0000268 LibVEX_ClearTemporary(False);
sewardjf48ac192004-10-29 00:41:29 +0000269 vex_traceflags = 0;
sewardjf13a16a2004-07-05 17:10:14 +0000270 return TransAccessFail;
271 }
sewardjaa59f942004-10-09 09:34:36 +0000272
273 /* If debugging, show the raw guest bytes for this bb. */
sewardjf48ac192004-10-29 00:41:29 +0000274 if (vex_traceflags & VEX_TRACE_FE) {
sewardjaa59f942004-10-09 09:34:36 +0000275 UChar* p = guest_bytes;
sewardjaa59f942004-10-09 09:34:36 +0000276 vex_printf(". 0 %llx %d\n.", guest_bytes_addr, *guest_bytes_read );
277 for (i = 0; i < *guest_bytes_read; i++)
278 vex_printf(" %02x", (Int)p[i] );
sewardjf48ac192004-10-29 00:41:29 +0000279 vex_printf("\n\n");
sewardjaa59f942004-10-09 09:34:36 +0000280 }
281
282 /* Sanity check the initial IR. */
sewardjcf787902004-11-03 09:08:33 +0000283 sanityCheckIRBB(irbb, guest_word_type);
sewardje8e9d732004-07-16 21:03:45 +0000284
sewardjedf4d692004-08-17 13:52:58 +0000285 /* Clean it up, hopefully a lot. */
sewardj8d2291c2004-10-25 14:50:21 +0000286 irbb = do_iropt_BB ( irbb, specHelper, preciseMemExnsFn,
287 guest_bytes_addr );
sewardjcf787902004-11-03 09:08:33 +0000288 sanityCheckIRBB(irbb, guest_word_type);
sewardjedf4d692004-08-17 13:52:58 +0000289
sewardjf48ac192004-10-29 00:41:29 +0000290 if (vex_traceflags & VEX_TRACE_OPT1) {
291 vex_printf("\n------------------------"
292 " After pre-instr IR optimisation "
293 "------------------------\n\n");
sewardjedf4d692004-08-17 13:52:58 +0000294 ppIRBB ( irbb );
295 vex_printf("\n");
296 }
297
sewardjf13a16a2004-07-05 17:10:14 +0000298 /* Get the thing instrumented. */
sewardj49651f42004-10-28 22:11:04 +0000299 if (instrument1)
sewardjcf787902004-11-03 09:08:33 +0000300 irbb = (*instrument1)(irbb, guest_layout, host_word_type);
sewardj49651f42004-10-28 22:11:04 +0000301 if (instrument2)
sewardjcf787902004-11-03 09:08:33 +0000302 irbb = (*instrument2)(irbb, guest_layout, host_word_type);
sewardj49651f42004-10-28 22:11:04 +0000303
sewardjf48ac192004-10-29 00:41:29 +0000304 if (vex_traceflags & VEX_TRACE_INST) {
305 vex_printf("\n------------------------"
306 " After instrumentation "
307 "------------------------\n\n");
308 ppIRBB ( irbb );
309 vex_printf("\n");
310 }
311
sewardj49651f42004-10-28 22:11:04 +0000312 if (instrument1 || instrument2)
sewardjcf787902004-11-03 09:08:33 +0000313 sanityCheckIRBB(irbb, guest_word_type);
sewardjf13a16a2004-07-05 17:10:14 +0000314
sewardj9578a8b2004-11-04 19:44:48 +0000315 /* Do a post-instrumentation cleanup pass. */
316 if (cleanup_after_instrumentation) {
317 do_deadcode_BB( irbb );
318 irbb = cprop_BB( irbb );
319 do_deadcode_BB( irbb );
320 sanityCheckIRBB(irbb, guest_word_type);
321 }
322
323 if (vex_traceflags & VEX_TRACE_OPT2) {
324 vex_printf("\n------------------------"
325 " After post-instr IR optimisation "
326 "------------------------\n\n");
327 ppIRBB ( irbb );
328 vex_printf("\n");
329 }
330
sewardjf13a16a2004-07-05 17:10:14 +0000331 /* Turn it into virtual-registerised code. */
sewardj49651f42004-10-28 22:11:04 +0000332 do_deadcode_BB( irbb );
333 do_treebuild_BB( irbb );
sewardjf48ac192004-10-29 00:41:29 +0000334
335 if (vex_traceflags & VEX_TRACE_TREES) {
336 vex_printf("\n------------------------"
337 " After tree-building "
338 "------------------------\n\n");
339 ppIRBB ( irbb );
340 vex_printf("\n");
341 }
342
343 if (vex_traceflags & VEX_TRACE_VCODE)
344 vex_printf("\n------------------------"
345 " Instruction selection "
346 "------------------------\n");
347
sewardj8ea867b2004-10-30 19:03:02 +0000348 vcode = iselBB ( irbb );
sewardjf13a16a2004-07-05 17:10:14 +0000349
sewardjf48ac192004-10-29 00:41:29 +0000350 if (vex_traceflags & VEX_TRACE_VCODE)
351 vex_printf("\n");
352
sewardjf48ac192004-10-29 00:41:29 +0000353 if (vex_traceflags & VEX_TRACE_VCODE) {
sewardj1f40a0a2004-07-21 12:28:07 +0000354 for (i = 0; i < vcode->arr_used; i++) {
355 vex_printf("%3d ", i);
356 ppInstr(vcode->arr[i]);
357 vex_printf("\n");
358 }
sewardjfbcaf332004-07-08 01:46:01 +0000359 vex_printf("\n");
360 }
sewardjfbcaf332004-07-08 01:46:01 +0000361
sewardjf13a16a2004-07-05 17:10:14 +0000362 /* Register allocate. */
363 rcode = doRegisterAllocation ( vcode, available_real_regs,
364 n_available_real_regs,
365 isMove, getRegUsage, mapRegs,
sewardj81ec4182004-10-25 23:15:52 +0000366 genSpill, genReload, guest_sizeB,
sewardj2b515872004-07-05 20:50:45 +0000367 ppInstr, ppReg );
sewardjf13a16a2004-07-05 17:10:14 +0000368
sewardjf48ac192004-10-29 00:41:29 +0000369 if (vex_traceflags & VEX_TRACE_RCODE) {
370 vex_printf("\n------------------------"
371 " Register-allocated code "
372 "------------------------\n\n");
sewardj1f40a0a2004-07-21 12:28:07 +0000373 for (i = 0; i < rcode->arr_used; i++) {
374 vex_printf("%3d ", i);
375 ppInstr(rcode->arr[i]);
376 vex_printf("\n");
377 }
sewardjfbcaf332004-07-08 01:46:01 +0000378 vex_printf("\n");
379 }
sewardjfbcaf332004-07-08 01:46:01 +0000380
sewardj81bd5502004-07-21 18:49:27 +0000381 /* Assemble */
sewardjf48ac192004-10-29 00:41:29 +0000382 if (vex_traceflags & VEX_TRACE_ASM) {
383 vex_printf("\n------------------------"
384 " Assembly "
385 "------------------------\n\n");
386 }
387
sewardj81bd5502004-07-21 18:49:27 +0000388 out_used = 0; /* tracks along the host_bytes array */
389 for (i = 0; i < rcode->arr_used; i++) {
sewardjf48ac192004-10-29 00:41:29 +0000390 if (vex_traceflags & VEX_TRACE_ASM) {
sewardjbad34a92004-07-22 01:14:11 +0000391 ppInstr(rcode->arr[i]);
392 vex_printf("\n");
393 }
sewardj81bd5502004-07-21 18:49:27 +0000394 j = (*emit)( insn_bytes, 32, rcode->arr[i] );
sewardjf48ac192004-10-29 00:41:29 +0000395 if (vex_traceflags & VEX_TRACE_ASM) {
sewardjbad34a92004-07-22 01:14:11 +0000396 for (k = 0; k < j; k++)
sewardj86898e82004-07-22 17:26:12 +0000397 if (insn_bytes[k] < 16)
398 vex_printf("0%x ", (UInt)insn_bytes[k]);
399 else
400 vex_printf("%x ", (UInt)insn_bytes[k]);
sewardjbad34a92004-07-22 01:14:11 +0000401 vex_printf("\n\n");
402 }
sewardj81bd5502004-07-21 18:49:27 +0000403 if (out_used + j > host_bytes_size) {
404 LibVEX_ClearTemporary(False);
sewardjf48ac192004-10-29 00:41:29 +0000405 vex_traceflags = 0;
sewardj81bd5502004-07-21 18:49:27 +0000406 return TransOutputFull;
407 }
408 for (k = 0; k < j; k++) {
409 host_bytes[out_used] = insn_bytes[k];
410 out_used++;
411 }
412 vassert(out_used <= host_bytes_size);
413 }
414 *host_bytes_used = out_used;
415
sewardj1f40a0a2004-07-21 12:28:07 +0000416 LibVEX_ClearTemporary(False);
sewardjf13a16a2004-07-05 17:10:14 +0000417
sewardjf48ac192004-10-29 00:41:29 +0000418 vex_traceflags = 0;
sewardj35421a32004-07-05 13:12:34 +0000419 return TransOK;
420}
421
422
423
424/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +0000425/*--- end main/vex_main.c ---*/
sewardj35421a32004-07-05 13:12:34 +0000426/*---------------------------------------------------------------*/