main_main.c revision f48ac19a67a98af44fe452c8c2be4192ac94b62d
1 2/*---------------------------------------------------------------*/ 3/*--- ---*/ 4/*--- This file (main/vex_main.c) is ---*/ 5/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ 6/*--- ---*/ 7/*---------------------------------------------------------------*/ 8 9#include "libvex.h" 10#include "libvex_guest_x86.h" 11 12#include "main/vex_globals.h" 13#include "main/vex_util.h" 14#include "host-generic/h_generic_regs.h" 15#include "host-x86/hdefs.h" 16#include "guest-x86/gdefs.h" 17#include "ir/iropt.h" 18 19 20/* This file contains the top level interface to the library. */ 21 22/* --------- Initialise the library. --------- */ 23 24/* Exported to library client. */ 25 26void LibVEX_default_VexControl ( /*OUT*/ VexControl* vcon ) 27{ 28 vcon->iropt_verbosity = 0; 29 vcon->iropt_level = 2; 30 vcon->iropt_precise_memory_exns = False; 31 vcon->iropt_unroll_thresh = 120; 32 vcon->guest_max_insns = 50; 33 vcon->guest_chase_thresh = 10; 34} 35 36 37/* Exported to library client. */ 38 39void LibVEX_Init ( 40 /* failure exit function */ 41 __attribute__ ((noreturn)) 42 void (*failure_exit) ( void ), 43 /* logging output function */ 44 void (*log_bytes) ( Char*, Int nbytes ), 45 /* debug paranoia level */ 46 Int debuglevel, 47 /* Are we supporting valgrind checking? */ 48 Bool valgrind_support, 49 /* Control ... */ 50 /*READONLY*/VexControl* vcon 51) 52{ 53 /* First off, do enough minimal setup so that the following 54 assertions can fail in a sane fashion, if need be. */ 55 vex_failure_exit = failure_exit; 56 vex_log_bytes = log_bytes; 57 58 /* Now it's safe to check parameters for sanity. */ 59 vassert(!vex_initdone); 60 vassert(failure_exit); 61 vassert(log_bytes); 62 vassert(debuglevel >= 0); 63 64 vassert(vcon->iropt_verbosity >= 0); 65 vassert(vcon->iropt_level >= 0); 66 vassert(vcon->iropt_level <= 2); 67 vassert(vcon->iropt_unroll_thresh >= 0); 68 vassert(vcon->iropt_unroll_thresh <= 400); 69 vassert(vcon->guest_max_insns >= 1); 70 vassert(vcon->guest_max_insns <= 100); 71 vassert(vcon->guest_chase_thresh >= 0); 72 vassert(vcon->guest_chase_thresh < vcon->guest_max_insns); 73 74 /* All the guest state structs must have an 8-aligned size. */ 75 vassert(0 == sizeof(VexGuestX86State) % 8); 76 77 /* Check that Vex has been built with sizes of basic types as 78 stated in priv/libvex_basictypes.h. Failure of any of these is 79 a serious configuration error and should be corrected 80 immediately. If any of these assertions fail you can fully 81 expect Vex not to work properly, if at all. */ 82 83 vassert(1 == sizeof(UChar)); 84 vassert(1 == sizeof(Char)); 85 vassert(2 == sizeof(UShort)); 86 vassert(2 == sizeof(Short)); 87 vassert(4 == sizeof(UInt)); 88 vassert(4 == sizeof(Int)); 89 vassert(8 == sizeof(ULong)); 90 vassert(8 == sizeof(Long)); 91 vassert(4 == sizeof(Float)); 92 vassert(8 == sizeof(Double)); 93 vassert(1 == sizeof(Bool)); 94 vassert(4 == sizeof(Addr32)); 95 vassert(8 == sizeof(Addr64)); 96 97 vassert(sizeof(void*) == 4 || sizeof(void*) == 8); 98 vassert(sizeof(void*) == sizeof(int*)); 99 vassert(sizeof(void*) == sizeof(HWord)); 100 101 /* Really start up .. */ 102 vex_debuglevel = debuglevel; 103 vex_valgrind_support = valgrind_support; 104 vex_control = *vcon; 105 vex_initdone = True; 106 LibVEX_SetAllocMode ( AllocModeTEMPORARY ); 107} 108 109 110/* --------- Make a translation. --------- */ 111 112/* Exported to library client. */ 113 114TranslateResult LibVEX_Translate ( 115 /* The instruction sets we are translating from and to. */ 116 InsnSet iset_guest, 117 InsnSet iset_host, 118 /* IN: the block to translate, and its guest address. */ 119 UChar* guest_bytes, 120 Addr64 guest_bytes_addr, 121 /* OUT: the number of bytes actually read */ 122 Int* guest_bytes_read, 123 /* IN: a place to put the resulting code, and its size */ 124 UChar* host_bytes, 125 Int host_bytes_size, 126 /* OUT: how much of the output area is used. */ 127 Int* host_bytes_used, 128 /* IN: optionally, two instrumentation functions. */ 129 IRBB* (*instrument1) ( IRBB*, VexGuestLayoutInfo* ), 130 IRBB* (*instrument2) ( IRBB*, VexGuestLayoutInfo* ), 131 HWord (*tool_findhelper) ( Char* ), 132 /* IN: optionally, an access check function for guest code. */ 133 Bool (*byte_accessible) ( Addr64 ), 134 /* IN: debug: trace vex activity at various points */ 135 Int traceflags 136) 137{ 138 /* This the bundle of functions we need to do the back-end stuff 139 (insn selection, reg-alloc, assembly) whilst being insulated 140 from the target instruction set. */ 141 HReg* available_real_regs; 142 Int n_available_real_regs; 143 Bool (*isMove) (HInstr*, HReg*, HReg*); 144 void (*getRegUsage) (HRegUsage*, HInstr*); 145 void (*mapRegs) (HRegRemap*, HInstr*); 146 HInstr* (*genSpill) ( HReg, Int ); 147 HInstr* (*genReload) ( HReg, Int ); 148 void (*ppInstr) ( HInstr* ); 149 void (*ppReg) ( HReg ); 150 HInstrArray* (*iselBB) ( IRBB*, HWord(*)(Char*), HWord(*)(Char*) ); 151 IRBB* (*bbToIR) ( UChar*, Addr64, Int*, 152 Bool(*)(Addr64), Bool ); 153 Int (*emit) ( UChar*, Int, HInstr* ); 154 HWord (*findHelper) ( Char* ); 155 IRExpr* (*specHelper) ( Char*, IRExpr** ); 156 Bool (*preciseMemExnsFn) ( Int, Int ); 157 158 VexGuestLayoutInfo* guest_layout; 159 Bool host_is_bigendian = False; 160 IRBB* irbb; 161 HInstrArray* vcode; 162 HInstrArray* rcode; 163 Int i, j, k, out_used, guest_sizeB; 164 UChar insn_bytes[32]; 165 IRType guest_word_size; 166 167 guest_layout = NULL; 168 available_real_regs = NULL; 169 n_available_real_regs = 0; 170 isMove = NULL; 171 getRegUsage = NULL; 172 mapRegs = NULL; 173 genSpill = NULL; 174 genReload = NULL; 175 ppInstr = NULL; 176 ppReg = NULL; 177 iselBB = NULL; 178 bbToIR = NULL; 179 emit = NULL; 180 findHelper = NULL; 181 specHelper = NULL; 182 preciseMemExnsFn = NULL; 183 guest_word_size = Ity_INVALID; 184 185 vex_traceflags = traceflags; 186 187 vassert(vex_initdone); 188 LibVEX_ClearTemporary(False); 189 190 /* First off, check that the guest and host insn sets 191 are supported. */ 192 switch (iset_host) { 193 case InsnSetX86: 194 getAllocableRegs_X86 ( &n_available_real_regs, 195 &available_real_regs ); 196 isMove = (Bool(*)(HInstr*,HReg*,HReg*)) isMove_X86Instr; 197 getRegUsage = (void(*)(HRegUsage*,HInstr*)) getRegUsage_X86Instr; 198 mapRegs = (void(*)(HRegRemap*,HInstr*)) mapRegs_X86Instr; 199 genSpill = (HInstr*(*)(HReg,Int)) genSpill_X86; 200 genReload = (HInstr*(*)(HReg,Int)) genReload_X86; 201 ppInstr = (void(*)(HInstr*)) ppX86Instr; 202 ppReg = (void(*)(HReg)) ppHRegX86; 203 iselBB = iselBB_X86; 204 emit = (Int(*)(UChar*,Int,HInstr*)) emit_X86Instr; 205 host_is_bigendian = False; 206 break; 207 default: 208 vpanic("LibVEX_Translate: unsupported target insn set"); 209 } 210 211 switch (iset_guest) { 212 case InsnSetX86: 213 preciseMemExnsFn = guest_x86_state_requires_precise_mem_exns; 214 bbToIR = bbToIR_X86Instr; 215 findHelper = x86guest_findhelper; 216 specHelper = x86guest_spechelper; 217 guest_sizeB = sizeof(VexGuestX86State); 218 guest_word_size = Ity_I32; 219 guest_layout = &x86guest_layout; 220 break; 221 default: 222 vpanic("LibVEX_Translate: unsupported guest insn set"); 223 } 224 225 if (vex_traceflags & VEX_TRACE_FE) 226 vex_printf("\n------------------------" 227 " Front end " 228 "------------------------\n\n"); 229 230 irbb = bbToIR ( guest_bytes, 231 guest_bytes_addr, 232 guest_bytes_read, 233 byte_accessible, 234 host_is_bigendian ); 235 236 if (irbb == NULL) { 237 /* Access failure. */ 238 LibVEX_ClearTemporary(False); 239 vex_traceflags = 0; 240 return TransAccessFail; 241 } 242 243 /* If debugging, show the raw guest bytes for this bb. */ 244 if (vex_traceflags & VEX_TRACE_FE) { 245 UChar* p = guest_bytes; 246 vex_printf(". 0 %llx %d\n.", guest_bytes_addr, *guest_bytes_read ); 247 for (i = 0; i < *guest_bytes_read; i++) 248 vex_printf(" %02x", (Int)p[i] ); 249 vex_printf("\n\n"); 250 } 251 252 /* Sanity check the initial IR. */ 253 sanityCheckIRBB(irbb, guest_word_size); 254 255 /* Clean it up, hopefully a lot. */ 256 irbb = do_iropt_BB ( irbb, specHelper, preciseMemExnsFn, 257 guest_bytes_addr ); 258 sanityCheckIRBB(irbb, guest_word_size); 259 260 if (vex_traceflags & VEX_TRACE_OPT1) { 261 vex_printf("\n------------------------" 262 " After pre-instr IR optimisation " 263 "------------------------\n\n"); 264 ppIRBB ( irbb ); 265 vex_printf("\n"); 266 } 267 268 /* Get the thing instrumented. */ 269 if (instrument1) 270 irbb = (*instrument1)(irbb, guest_layout); 271 if (instrument2) 272 irbb = (*instrument2)(irbb, guest_layout); 273 274 if (vex_traceflags & VEX_TRACE_INST) { 275 vex_printf("\n------------------------" 276 " After instrumentation " 277 "------------------------\n\n"); 278 ppIRBB ( irbb ); 279 vex_printf("\n"); 280 } 281 282 if (instrument1 || instrument2) 283 sanityCheckIRBB(irbb, guest_word_size); 284 285 /* Turn it into virtual-registerised code. */ 286 do_deadcode_BB( irbb ); 287 do_treebuild_BB( irbb ); 288 289 if (vex_traceflags & VEX_TRACE_TREES) { 290 vex_printf("\n------------------------" 291 " After tree-building " 292 "------------------------\n\n"); 293 ppIRBB ( irbb ); 294 vex_printf("\n"); 295 } 296 297 if (vex_traceflags & VEX_TRACE_VCODE) 298 vex_printf("\n------------------------" 299 " Instruction selection " 300 "------------------------\n"); 301 302 vcode = iselBB ( irbb, findHelper, tool_findhelper ); 303 304 if (vex_traceflags & VEX_TRACE_VCODE) 305 vex_printf("\n"); 306 307#if 0 308 if (vex_traceflags & VEX_TRACE_VCODE) { 309 vex_printf("\n-------- Virtual registerised code --------\n"); 310 for (i = 0; i < vcode->arr_used; i++) { 311 vex_printf("%3d ", i); 312 ppInstr(vcode->arr[i]); 313 vex_printf("\n"); 314 } 315 vex_printf("\n"); 316 } 317#endif 318 319 /* Register allocate. */ 320 rcode = doRegisterAllocation ( vcode, available_real_regs, 321 n_available_real_regs, 322 isMove, getRegUsage, mapRegs, 323 genSpill, genReload, guest_sizeB, 324 ppInstr, ppReg ); 325 326 if (vex_traceflags & VEX_TRACE_RCODE) { 327 vex_printf("\n------------------------" 328 " Register-allocated code " 329 "------------------------\n\n"); 330 for (i = 0; i < rcode->arr_used; i++) { 331 vex_printf("%3d ", i); 332 ppInstr(rcode->arr[i]); 333 vex_printf("\n"); 334 } 335 vex_printf("\n"); 336 } 337 338 /* Assemble */ 339 if (vex_traceflags & VEX_TRACE_ASM) { 340 vex_printf("\n------------------------" 341 " Assembly " 342 "------------------------\n\n"); 343 } 344 345 out_used = 0; /* tracks along the host_bytes array */ 346 for (i = 0; i < rcode->arr_used; i++) { 347 if (vex_traceflags & VEX_TRACE_ASM) { 348 ppInstr(rcode->arr[i]); 349 vex_printf("\n"); 350 } 351 j = (*emit)( insn_bytes, 32, rcode->arr[i] ); 352 if (vex_traceflags & VEX_TRACE_ASM) { 353 for (k = 0; k < j; k++) 354 if (insn_bytes[k] < 16) 355 vex_printf("0%x ", (UInt)insn_bytes[k]); 356 else 357 vex_printf("%x ", (UInt)insn_bytes[k]); 358 vex_printf("\n\n"); 359 } 360 if (out_used + j > host_bytes_size) { 361 LibVEX_ClearTemporary(False); 362 vex_traceflags = 0; 363 return TransOutputFull; 364 } 365 for (k = 0; k < j; k++) { 366 host_bytes[out_used] = insn_bytes[k]; 367 out_used++; 368 } 369 vassert(out_used <= host_bytes_size); 370 } 371 *host_bytes_used = out_used; 372 373 LibVEX_ClearTemporary(False); 374 375 vex_traceflags = 0; 376 return TransOK; 377} 378 379 380 381/*---------------------------------------------------------------*/ 382/*--- end main/vex_main.c ---*/ 383/*---------------------------------------------------------------*/ 384