github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/lift/x86/argument.go (about) 1 package x86 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/decomp/exp/bin" 9 "github.com/decomp/exp/disasm/x86" 10 "github.com/kr/pretty" 11 "github.com/llir/llvm/ir" 12 "github.com/llir/llvm/ir/constant" 13 "github.com/llir/llvm/ir/enum" 14 "github.com/llir/llvm/ir/metadata" 15 "github.com/llir/llvm/ir/types" 16 "github.com/llir/llvm/ir/value" 17 "golang.org/x/arch/x86/x86asm" 18 ) 19 20 // === [ argument ] ============================================================ 21 22 // useArg returns the value held by the given argument, emitting code to f. 23 func (f *Func) useArg(arg *x86.Arg) value.Value { 24 switch a := arg.Arg.(type) { 25 case x86asm.Reg: 26 reg := x86.NewReg(a, arg.Parent) 27 return f.useReg(reg) 28 case x86asm.Mem: 29 mem := x86.NewMem(a, arg.Parent) 30 return f.useMem(mem) 31 case x86asm.Imm: 32 return constant.NewInt(types.I32, int64(a)) 33 case x86asm.Rel: 34 next := arg.Parent.Addr + bin.Address(arg.Parent.Len) 35 addr := next + bin.Address(a) 36 return f.useAddr(addr) 37 default: 38 panic(fmt.Errorf("support for argument type %T not yet implemented", arg.Arg)) 39 } 40 } 41 42 // useArgElem returns a value of the specified element type held by the given 43 // argument, emitting code to f. 44 func (f *Func) useArgElem(arg *x86.Arg, elem types.Type) value.Value { 45 switch a := arg.Arg.(type) { 46 case x86asm.Reg: 47 reg := x86.NewReg(a, arg.Parent) 48 return f.useRegElem(reg, elem) 49 case x86asm.Mem: 50 mem := x86.NewMem(a, arg.Parent) 51 return f.useMemElem(mem, elem) 52 //case x86asm.Imm: 53 //case x86asm.Rel: 54 default: 55 panic(fmt.Errorf("support for argument type %T not yet implemented", arg)) 56 } 57 } 58 59 // defArg stores the value to the given argument, emitting code to f. 60 func (f *Func) defArg(arg *x86.Arg, v value.Value) { 61 switch a := arg.Arg.(type) { 62 case x86asm.Reg: 63 reg := x86.NewReg(a, arg.Parent) 64 f.defReg(reg, v) 65 case x86asm.Mem: 66 mem := x86.NewMem(a, arg.Parent) 67 f.defMem(mem, v) 68 //case x86asm.Imm: 69 //case x86asm.Rel: 70 default: 71 panic(fmt.Errorf("support for argument type %T not yet implemented", arg)) 72 } 73 } 74 75 // defArgElem stores the value of the specified element type to the given 76 // argument, emitting code to f. 77 func (f *Func) defArgElem(arg *x86.Arg, v value.Value, elem types.Type) { 78 switch a := arg.Arg.(type) { 79 case x86asm.Reg: 80 reg := x86.NewReg(a, arg.Parent) 81 f.defRegElem(reg, v, elem) 82 case x86asm.Mem: 83 mem := x86.NewMem(a, arg.Parent) 84 f.defMemElem(mem, v, elem) 85 //case x86asm.Imm: 86 //case x86asm.Rel: 87 default: 88 panic(fmt.Errorf("support for argument type %T not yet implemented", arg)) 89 } 90 } 91 92 // === [ register ] ============================================================ 93 94 // useReg loads and returns a value from the given x86 register, emitting code 95 // to f. 96 func (f *Func) useReg(reg *x86.Reg) value.Named { 97 src := f.reg(reg.Reg) 98 return f.cur.NewLoad(src) 99 } 100 101 // useRegElem loads and returns a value of the specified element type from the 102 // given x86 register, emitting code to f. 103 func (f *Func) useRegElem(reg *x86.Reg, elem types.Type) value.Value { 104 src := f.reg(reg.Reg) 105 typ := types.NewPointer(elem) 106 if !typ.Equal(src.Type()) { 107 src = f.cur.NewBitCast(src, typ) 108 } 109 return f.cur.NewLoad(src) 110 } 111 112 // defReg stores the value to the given x86 register, emitting code to f. 113 func (f *Func) defReg(reg *x86.Reg, v value.Value) { 114 dst := f.reg(reg.Reg) 115 f.cur.NewStore(v, dst) 116 switch reg.Reg { 117 case x86asm.EAX, x86asm.EDX: 118 // Redefine the PSEUDO-register EDX:EAX based on change in EAX or EDX. 119 f.redefEDX_EAX() 120 } 121 } 122 123 // defRegElem stores the value of the specified element type to the given x86 124 // register, emitting code to f. 125 func (f *Func) defRegElem(reg *x86.Reg, v value.Value, elem types.Type) { 126 dst := f.reg(reg.Reg) 127 typ := types.NewPointer(elem) 128 if !typ.Equal(dst.Type()) { 129 dst = f.cur.NewBitCast(dst, typ) 130 } 131 f.cur.NewStore(v, dst) 132 } 133 134 // reg returns a pointer to the LLVM IR value associated with the given x86 135 // register. 136 func (f *Func) reg(reg x86asm.Reg) value.Value { 137 if v, ok := f.regs[reg]; ok { 138 return v 139 } 140 typ := regType(reg) 141 v := ir.NewAlloca(typ) 142 name := strings.ToLower(x86.Register(reg).String()) 143 v.SetName(name) 144 f.regs[reg] = v 145 return v 146 } 147 148 // === [ memory reference ] ==================================================== 149 150 // useMem loads and returns the value of the given memory reference, emitting 151 // code to f. 152 func (f *Func) useMem(mem *x86.Mem) value.Named { 153 src := f.mem(mem) 154 v := f.cur.NewLoad(src) 155 if mem.Parent != nil && mem.Parent.MemBytes != 0 { 156 if t, ok := src.Type().(*types.PointerType); ok { 157 var indices []uint64 158 elemType := t.ElemType 159 for { 160 switch e := elemType.(type) { 161 case *types.ArrayType: 162 indices = append(indices, 0) 163 elemType = e.ElemType 164 continue 165 case *types.StructType: 166 indices = append(indices, 0) 167 elemType = e.Fields[0] 168 continue 169 } 170 break 171 } 172 if len(indices) > 0 { 173 return f.cur.NewExtractValue(v, indices...) 174 } 175 } 176 } 177 return v 178 } 179 180 // useMemElem loads and returns a value of the specified element type from the 181 // given memory reference, emitting code to f. 182 func (f *Func) useMemElem(mem *x86.Mem, elem types.Type) value.Value { 183 src := f.mem(mem) 184 typ := types.NewPointer(elem) 185 if !typ.Equal(src.Type()) { 186 src = f.cur.NewBitCast(src, typ) 187 } 188 return f.cur.NewLoad(src) 189 } 190 191 // defMem stores the value to the given memory reference, emitting code to f. 192 func (f *Func) defMem(mem *x86.Mem, v value.Value) { 193 dst := f.mem(mem) 194 // Bitcast pointer to appropriate size. 195 dst = f.castToPtr(dst, mem.Parent) 196 f.cur.NewStore(v, dst) 197 } 198 199 // defMemElem stores the value of the specified element type to the given memory 200 // reference, emitting code to f. 201 func (f *Func) defMemElem(mem *x86.Mem, v value.Value, elem types.Type) { 202 dst := f.mem(mem) 203 typ := types.NewPointer(elem) 204 if !typ.Equal(dst.Type()) { 205 dst = f.cur.NewBitCast(dst, typ) 206 } 207 f.cur.NewStore(v, dst) 208 } 209 210 // mem returns a pointer to the LLVM IR value associated with the given memory 211 // argument, emitting code to f. 212 func (f *Func) mem(mem *x86.Mem) value.Value { 213 // Segment:[Base+Scale*Index+Disp]. 214 var ( 215 segment value.Value 216 base value.Value 217 index value.Value 218 disp value.Value 219 ) 220 if mem.Mem.Segment != 0 { 221 segment = f.useReg(mem.Segment()) 222 } 223 224 // Parse Base register. 225 var rel bin.Address 226 switch mem.Mem.Base { 227 case 0: 228 // no base register. 229 case x86asm.IP, x86asm.EIP, x86asm.RIP: 230 // Handle IP-relative addressing; common in 64-bit x86. 231 rel = mem.Parent.Addr + bin.Address(mem.Parent.Len) 232 default: 233 base = f.useReg(mem.Base()) 234 } 235 if mem.Mem.Index != 0 { 236 index = f.useReg(mem.Index()) 237 } 238 239 // TODO: Add proper support for memory references. 240 // Segment Reg 241 // Base Reg 242 // Scale uint8 243 // Index Reg 244 // Disp int64 245 246 // Handle local variables. 247 if segment == nil && index == nil { 248 // Stack local memory access. 249 switch mem.Mem.Base { 250 case x86asm.ESP, x86asm.EBP: 251 name := fmt.Sprintf("%s_%d", strings.ToLower(x86.Register(mem.Mem.Base).String()), f.espDisp+mem.Disp) 252 if v, ok := f.locals[name]; ok { 253 return v 254 } 255 v := ir.NewAlloca(types.I32) 256 v.SetName(name) 257 f.locals[name] = v 258 dbg.Printf("local %v of %q: %v\n", name, f.Ident(), v) 259 return v 260 } 261 } 262 263 // Handle disposition. 264 if mem.Disp != 0 { 265 if context, ok := f.l.Contexts[mem.Parent.Addr]; ok { 266 if c, ok := context.Args[mem.OpIndex]; ok { 267 if o, ok := c["Mem.offset"]; ok { 268 offset := o.Int64() 269 addr := rel + bin.Address(mem.Disp-offset) 270 v, ok := f.addr(addr) 271 if !ok { 272 panic(fmt.Errorf("unable to locate value at address %v; referenced from %v instruction at %v", addr, mem.Parent.Op, mem.Parent.Addr)) 273 } 274 // TODO: Figure out how to handle negative offsets. 275 if offset < 0 { 276 disp = v 277 } else { 278 disp = f.getElementPtr(v, uint64(offset)) 279 } 280 } 281 } 282 } 283 if disp == nil { 284 addr := rel + bin.Address(mem.Disp) 285 v, ok := f.addr(addr) 286 if !ok { 287 warn.Printf("unable to locate value at address %v; referenced from %v instruction at %v", addr, mem.Parent.Op, mem.Parent.Addr) 288 } 289 disp = v 290 } 291 } 292 293 // Early return for direct memory access. 294 if segment == nil && base == nil && index == nil { 295 if disp == nil { 296 addr := rel + bin.Address(mem.Disp) 297 // TODO: Remove once the lift library matures a bit. 298 warn.Printf("unknown global variable type at address %v; guessing i32", addr) 299 name := fmt.Sprintf("g_%06X", uint64(addr)) 300 contentType := types.I32 301 typ := types.NewPointer(contentType) 302 g := &ir.Global{ 303 Typ: typ, 304 ContentType: contentType, 305 Init: constant.NewZeroInitializer(contentType), 306 } 307 g.SetName(name) 308 md := &metadata.Attachment{ 309 Name: "addr", 310 Node: &metadata.Tuple{ 311 Fields: []metadata.Field{&metadata.String{Value: addr.String()}}, 312 }, 313 } 314 g.Metadata = append(g.Metadata, md) 315 // TODO: don't write to f.l from here as it should be read-only to 316 // allow for concurrent execution. 317 f.l.Globals[addr] = g 318 return g 319 panic(fmt.Errorf("unable to locate value at address %v; referenced from %v instruction at %v", addr, mem.Parent.Op, mem.Parent.Addr)) 320 } 321 return disp 322 } 323 324 // TODO: Handle Segment. 325 src := disp 326 if segment != nil { 327 // Ignore segments for now, assume byte addressing. 328 //pretty.Println(mem) 329 //panic("support for memory reference segment not yet implemented") 330 } 331 332 // Handle Base. 333 if base != nil { 334 if src == nil { 335 src = base 336 } else { 337 src = f.castToPtr(src, mem.Parent) 338 indices := []value.Value{base} 339 src = f.cur.NewGetElementPtr(src, indices...) 340 } 341 } 342 343 // TODO: Handle Scale*Index. 344 if index != nil { 345 // TODO: Figure out how to handle scale. If we can validate that gep 346 // indexes into elements of size `scale`, the scale can be safely ignored. 347 if src == nil { 348 src = index 349 } else { 350 src = f.castToPtr(src, mem.Parent) 351 indices := []value.Value{index} 352 src = f.cur.NewGetElementPtr(src, indices...) 353 } 354 } 355 356 // Handle dynamic memory reference. 357 if src == nil { 358 pretty.Println(mem) 359 panic("unable to locate memory reference") 360 } 361 362 // TODO: Cast into proper type, once type analysis information is available. 363 364 // Force bitcast into pointer type. 365 return f.castToPtr(src, mem.Parent) 366 } 367 368 // castToPtr casts the given value into a pointer, where the element type is 369 // derrived from src and instruction prefixes, with instruction prefix takes 370 // precedence. 371 func (f *Func) castToPtr(src value.Value, parent *x86.Inst) value.Value { 372 elem := src.Type() 373 var preBitSize uint64 374 if typ, ok := src.Type().(*types.PointerType); ok { 375 elem = typ.ElemType 376 if elem, ok := elem.(*types.IntType); ok { 377 preBitSize = elem.BitSize 378 } 379 } 380 // Derive element size from the parent instruction. 381 var bitSize uint64 382 if parent != nil { 383 if parent.MemBytes != 0 { 384 bitSize = uint64(parent.MemBytes) * 8 385 } 386 for _, prefix := range parent.Prefix[:] { 387 // The first zero in the array marks the end of the prefixes. 388 if prefix == 0 { 389 break 390 } 391 switch prefix &^ x86asm.PrefixImplicit { 392 case x86asm.PrefixData16: 393 bitSize = 16 394 case x86asm.PrefixREP, x86asm.PrefixREPN: 395 // nothing to do. 396 case x86asm.PrefixREX | x86asm.PrefixREXW: 397 // TODO: Implement support for REX.W 398 default: 399 panic(fmt.Errorf("support for prefix %v (0x%04X) not yet implemented", prefix, uint16(prefix))) 400 } 401 } 402 } 403 if bitSize != 0 { 404 elem = types.NewInt(bitSize) 405 } 406 needCast := !types.IsPointer(src.Type()) 407 if bitSize != 0 && preBitSize != 0 && bitSize != preBitSize { 408 needCast = true 409 } 410 if needCast { 411 typ := types.NewPointer(elem) 412 var s string 413 if v, ok := src.(value.Named); ok { 414 if name := v.Name(); len(name) > 0 { 415 s = fmt.Sprintf(" %q", name) 416 } 417 } 418 dbg.Printf("casting%s to pointer type: %v", s, typ) 419 return f.cur.NewBitCast(src, typ) 420 } 421 return src 422 } 423 424 // === [ status flag ] ========================================================= 425 426 // StatusFlag represents the set of status flags. 427 type StatusFlag uint 428 429 // Status flags. 430 const ( 431 firstStatusFlag = CF 432 433 CF StatusFlag = iota // Carry Flag 434 PF // Parity Flag 435 AF // Auxiliary Carry Flag 436 ZF // Zero Flag 437 SF // Sign Flag 438 OF // Overflow Flag 439 440 lastStatusFlag = OF 441 ) 442 443 // String returns the string representation of the status flag. 444 func (status StatusFlag) String() string { 445 m := map[StatusFlag]string{ 446 CF: "CF", 447 PF: "PF", 448 AF: "AF", 449 ZF: "ZF", 450 SF: "SF", 451 OF: "OF", 452 } 453 if s, ok := m[status]; ok { 454 return s 455 } 456 return fmt.Sprintf("unknown status flag %d", uint(status)) 457 } 458 459 // useStatus loads and returns the value of the given x86 status flag, emitting 460 // code to f. 461 func (f *Func) useStatus(status StatusFlag) value.Value { 462 src := f.status(status) 463 return f.cur.NewLoad(src) 464 } 465 466 // defStatus stores the value to the given x86 status flag, emitting code to f. 467 func (f *Func) defStatus(status StatusFlag, v value.Value) { 468 dst := f.status(status) 469 f.cur.NewStore(v, dst) 470 } 471 472 // status returns a pointer to the LLVM IR value associated with the given x86 473 // status flag. 474 func (f *Func) status(status StatusFlag) value.Value { 475 if v, ok := f.statusFlags[status]; ok { 476 return v 477 } 478 v := ir.NewAlloca(types.I1) 479 name := strings.ToLower(status.String()) 480 v.SetName(name) 481 f.statusFlags[status] = v 482 return v 483 } 484 485 // === [ FPU status flag ] ===================================================== 486 487 // FStatusFlag represents the set of FPU status flags. 488 type FStatusFlag uint 489 490 // FPU status flags. 491 const ( 492 fpuFirstStatusFlag = Busy 493 494 Busy FStatusFlag = iota // FPU Busy 495 C0 // Condition Code 0 496 C1 // Condition Code 1 497 C2 // Condition Code 2 498 C3 // Condition Code 3 499 ES // Exception Summary Status 500 StackFault // Stack Fault 501 // Exception Flags. 502 PE // Precision 503 UE // Underflow 504 OE // Overflow 505 ZE // Zero Divide 506 DE // Denormalized Operand 507 IE // Invalid Operation 508 509 fpuLastStatusFlag = IE 510 ) 511 512 // String returns the string representation of the status flag. 513 func (fstatus FStatusFlag) String() string { 514 m := map[FStatusFlag]string{ 515 Busy: "x87_B", 516 C0: "x87_C0", 517 C1: "x87_C1", 518 C2: "x87_C2", 519 C3: "x87_C3", 520 ES: "x87_ES", 521 StackFault: "x87_SF", 522 PE: "x87_PE", 523 UE: "x87_UE", 524 OE: "x87_OE", 525 ZE: "x87_ZE", 526 DE: "x87_DE", 527 IE: "x87_IE", 528 } 529 if s, ok := m[fstatus]; ok { 530 return s 531 } 532 return fmt.Sprintf("unknown status flag %d", uint(fstatus)) 533 } 534 535 // useFStatus loads and returns the value of the given x87 FPU status flag, 536 // emitting code to f. 537 func (f *Func) useFStatus(fstatus FStatusFlag) value.Value { 538 src := f.fstatus(fstatus) 539 return f.cur.NewLoad(src) 540 } 541 542 // defFStatus stores the value to the given x87 FPU status flag, emitting code 543 // to f. 544 func (f *Func) defFStatus(fstatus FStatusFlag, v value.Value) { 545 dst := f.fstatus(fstatus) 546 f.cur.NewStore(v, dst) 547 } 548 549 // fstatus returns a pointer to the LLVM IR value associated with the given x87 550 // FPU status flag. 551 func (f *Func) fstatus(fstatus FStatusFlag) value.Value { 552 if v, ok := f.fstatusFlags[fstatus]; ok { 553 return v 554 } 555 v := ir.NewAlloca(types.I1) 556 name := strings.ToLower(fstatus.String()) 557 v.SetName(name) 558 f.fstatusFlags[fstatus] = v 559 return v 560 } 561 562 // === [ address ] ============================================================= 563 564 // useAddr loads and returns the value of the given address, emitting code to f. 565 func (f *Func) useAddr(addr bin.Address) value.Named { 566 src, ok := f.addr(addr) 567 if !ok { 568 panic(fmt.Errorf("unable to locate value at address %v", addr)) 569 } 570 return f.cur.NewLoad(src) 571 } 572 573 // defAddr stores the value to the given address, emitting code to f. 574 func (f *Func) defAddr(addr bin.Address, v value.Value) { 575 dst, ok := f.addr(addr) 576 if !ok { 577 panic(fmt.Errorf("unable to locate value at address %v", addr)) 578 } 579 f.cur.NewStore(v, dst) 580 } 581 582 // addr returns a pointer to the LLVM IR value associated with the given 583 // address, emitting code to f. The returned value is one of *ir.BasicBlock, 584 // *ir.Global and *ir.Function, and the boolean value indicates success 585 func (f *Func) addr(addr bin.Address) (value.Named, bool) { 586 if block, ok := f.blocks[addr]; ok { 587 return block, true 588 } 589 // Direct or indirect access to global variable. 590 if g, ok := f.global(addr); ok { 591 return g, true 592 } 593 if fn, ok := f.l.Funcs[addr]; ok { 594 return fn.Func, true 595 } 596 // TODO: Add support for lookup of more globally addressable values. 597 return nil, false 598 } 599 600 // global returns a pointer to the LLVM IR value associated with the given 601 // global variable address, and a boolean value indicating success. 602 func (f *Func) global(addr bin.Address) (value.Named, bool) { 603 // Early return if direct access to global variable. 604 if src, ok := f.l.Globals[addr]; ok { 605 return src, true 606 } 607 608 // Use binary search if indirect access to global variable (e.g. struct 609 // field, array element). 610 var globalAddrs []bin.Address 611 for globalAddr := range f.l.Globals { 612 globalAddrs = append(globalAddrs, globalAddr) 613 } 614 sort.Sort(bin.Addresses(globalAddrs)) 615 less := func(i int) bool { 616 return addr < globalAddrs[i] 617 } 618 index := sort.Search(len(globalAddrs), less) 619 index-- 620 if 0 <= index && index < len(globalAddrs) { 621 start := globalAddrs[index] 622 g := f.l.Globals[start] 623 size := f.l.sizeOfType(g.Typ.ElemType) 624 end := start + bin.Address(size) 625 if start <= addr && addr < end { 626 offset := uint64(addr - start) 627 return f.getElementPtr(g, offset), true 628 } 629 } 630 return nil, false 631 } 632 633 // ### [ helpers ] ############################################################# 634 635 // getAddr returns the static address represented by the given argument, and a 636 // boolean indicating success. 637 func (f *Func) getAddr(arg *x86.Arg) (bin.Address, bool) { 638 switch a := arg.Arg.(type) { 639 case x86asm.Reg: 640 if context, ok := f.l.Contexts[arg.Parent.Addr]; ok { 641 if c, ok := context.Regs[x86.Register(a)]; ok { 642 if addr, ok := c["addr"]; ok { 643 return addr.Addr(), true 644 } 645 panic(fmt.Errorf("support for register context `%v` not yet implemented", c)) 646 } 647 } 648 case x86asm.Rel: 649 next := arg.Parent.Addr + bin.Address(arg.Parent.Len) 650 addr := next + bin.Address(a) 651 return addr, true 652 case x86asm.Mem: 653 if a.Segment == 0 && a.Base == 0 && a.Scale == 0 && a.Index == 0 { 654 return bin.Address(a.Disp), true 655 } 656 } 657 return 0, false 658 } 659 660 // getFunc resolves the function, function type, and calling convention of the 661 // given argument. The boolean return value indicates success. 662 func (f *Func) getFunc(arg *x86.Arg) (value.Named, *types.FuncType, enum.CallingConv, bool) { 663 // Check if register symbol context present. 664 switch a := arg.Arg.(type) { 665 case x86asm.Reg: 666 if context, ok := f.l.Contexts[arg.Parent.Addr]; ok { 667 if c, ok := context.Regs[x86.Register(a)]; ok { 668 if symbol, ok := c["symbol"]; ok { 669 fname := symbol.String() 670 fn, ok := f.l.FuncByName[fname] 671 if !ok { 672 panic(fmt.Errorf("unable to locate external function %q", fname)) 673 } 674 return fn, fn.Sig, fn.CallingConv, true 675 } 676 // TODO: Remove poor man's type propagation once the type analysis and 677 // data flow analysis phases have been properly implemented. 678 if param, ok := c["param"]; ok { 679 p := param.Int64() 680 if p >= int64(len(f.Params)) { 681 panic(fmt.Errorf("invalid function parameter index; expected < %d, got %d", len(f.Params), p)) 682 } 683 v := f.Params[p] 684 typ := v.Type() 685 ptr, ok := typ.(*types.PointerType) 686 if !ok { 687 panic(fmt.Errorf("invalid function pointer type of function parameter %q referenced from instruction at address %v; expected *types.PointerType, got %T; ", f.Params[p].Ident(), arg.Parent.Addr, typ)) 688 } 689 sig, ok := ptr.ElemType.(*types.FuncType) 690 if !ok { 691 panic(fmt.Errorf("invalid function type of function parameter %q referenced from instruction at address %v; expected *types.FuncType, got %T; ", f.Params[p].Ident(), arg.Parent.Addr, ptr.ElemType)) 692 } 693 // TODO: Figure out how to recover calling convention. 694 // Perhaps through context.json at call sites? 695 return v, sig, enum.CallingConvNone, true 696 } 697 } 698 } 699 } 700 701 if addr, ok := f.getAddr(arg); ok { 702 if fn, ok := f.l.Funcs[addr]; ok { 703 v := fn.Func 704 return v, v.Sig, v.CallingConv, true 705 } 706 if g, ok := f.l.Globals[addr]; ok { 707 ptr, ok := g.Typ.ElemType.(*types.PointerType) 708 if !ok { 709 panic(fmt.Errorf("invalid function pointer type of global variable at address %v referenced from instruction at address %v; expected *types.PointerType, got %T; ", addr, arg.Parent.Addr, g.Typ.ElemType)) 710 } 711 sig, ok := ptr.ElemType.(*types.FuncType) 712 if !ok { 713 panic(fmt.Errorf("invalid function type of global variable at address %v referenced from instruction at address %v; expected *types.FuncType, got %T; ", addr, arg.Parent.Addr, ptr.ElemType)) 714 } 715 v := f.cur.NewLoad(g) 716 // TODO: Figure out how to recover calling convention. 717 // Perhaps through context.json at call sites? 718 return v, sig, enum.CallingConvNone, true 719 } 720 panic(fmt.Errorf("unable to locate function at address %v referenced from instruction at address %v", addr, arg.Parent.Addr)) 721 } 722 723 // Handle function pointers in structures. 724 switch a := arg.Arg.(type) { 725 case x86asm.Mem: 726 if a.Base != 0 { 727 context, ok := f.l.Contexts[arg.Parent.Addr] 728 if !ok { 729 pretty.Println(arg.Arg) 730 panic(fmt.Errorf("unable to locate context for %v register used at %v", a.Base, arg.Parent.Addr)) 731 } 732 if c, ok := context.Regs[x86.Register(a.Base)]; ok { 733 if typStr, ok := c["type"]; ok { 734 typ := f.l.parseType(typStr.String()) 735 dbg.Println("context type:", typ) 736 reg := f.reg(a.Base) 737 var v value.Named = f.cur.NewBitCast(reg, typ) 738 v = f.cur.NewLoad(v) 739 // TODO: Figure out how to handle negative offsets. 740 v = f.getElementPtr(v, uint64(a.Disp)) 741 v = f.cur.NewLoad(v) 742 if typ, ok := v.Type().(*types.PointerType); ok { 743 if sig := typ.ElemType.(*types.FuncType); ok { 744 // TODO: Figure out how to recover calling convention. 745 // Perhaps through context.json at call sites? 746 return v, sig, enum.CallingConvNone, true 747 } 748 } 749 panic(fmt.Errorf("invalid callee type; expected pointer to function type, got %v", v.Type())) 750 } 751 if addr, ok := c["addr"]; ok { 752 v := f.useAddr(addr.Addr()) 753 // HACK: Remove once proper type and data flow analysis has been 754 // implemented. 755 if extractvalue, ok := c["extractvalue"]; ok && extractvalue.Bool() { 756 dbg.Println("extractvalue:", v) 757 dbg.Println("extractvalue.Type():", v.Type()) 758 // TODO: Handle index based on Index regster if present. 759 v = f.cur.NewExtractValue(v, 0) 760 } 761 // TODO: Figure out how to handle negative offsets. 762 v = f.getElementPtr(v, uint64(a.Disp)) 763 v = f.cur.NewLoad(v) 764 if typ, ok := v.Type().(*types.PointerType); ok { 765 if sig := typ.ElemType.(*types.FuncType); ok { 766 // TODO: Figure out how to recover calling convention. 767 // Perhaps through context.json at call sites? 768 return v, sig, enum.CallingConvNone, true 769 } 770 } 771 panic(fmt.Errorf("invalid callee type; expected pointer to function type, got %v", v.Type())) 772 } 773 if min, ok := c["min"]; ok { 774 addr := bin.Address(a.Disp + min.Int64()) 775 v := f.useAddr(addr) 776 if typ, ok := v.Type().(*types.PointerType); ok { 777 if sig := typ.ElemType.(*types.FuncType); ok { 778 // TODO: Figure out how to recover calling convention. 779 // Perhaps through context.json at call sites? 780 return v, sig, enum.CallingConvNone, true 781 } 782 } 783 panic(fmt.Errorf("invalid callee type; expected pointer to function type, got %v", v.Type())) 784 } 785 } 786 787 if c, ok := context.Args[arg.OpIndex]; ok { 788 // TODO: Remove poor man's type propagation once the type analysis and 789 // data flow analysis phases have been properly implemented. 790 if param, ok := c["param"]; ok { 791 p := param.Int64() 792 if p >= int64(len(f.Params)) { 793 panic(fmt.Errorf("invalid function parameter index; expected < %d, got %d", len(f.Params), p)) 794 } 795 v := f.Params[p] 796 typ := v.Type() 797 ptr, ok := typ.(*types.PointerType) 798 if !ok { 799 panic(fmt.Errorf("invalid function pointer type of function parameter %q referenced from instruction at address %v; expected *types.PointerType, got %T; ", f.Params[p].Ident(), arg.Parent.Addr, typ)) 800 } 801 sig, ok := ptr.ElemType.(*types.FuncType) 802 if !ok { 803 panic(fmt.Errorf("invalid function type of function parameter %q referenced from instruction at address %v; expected *types.FuncType, got %T; ", f.Params[p].Ident(), arg.Parent.Addr, ptr.ElemType)) 804 } 805 // TODO: Figure out how to recover calling convention. 806 // Perhaps through context.json at call sites? 807 return v, sig, enum.CallingConvNone, true 808 } 809 } 810 811 } 812 if a.Index != 0 { 813 context, ok := f.l.Contexts[arg.Parent.Addr] 814 if !ok { 815 pretty.Println(arg.Arg) 816 panic(fmt.Errorf("unable to locate context for %v register used at %v", a.Index, arg.Parent.Addr)) 817 } 818 if c, ok := context.Regs[x86.Register(a.Index)]; ok { 819 if min, ok := c["min"]; ok { 820 addr := bin.Address(a.Disp + int64(a.Scale)*min.Int64()) 821 v := f.useAddr(addr) 822 if typ, ok := v.Type().(*types.PointerType); ok { 823 if sig := typ.ElemType.(*types.FuncType); ok { 824 // TODO: Figure out how to recover calling convention. 825 // Perhaps through context.json at call sites? 826 return v, sig, enum.CallingConvNone, true 827 } 828 } 829 // HACK: Use gep as a fallback for 0 element offsets. 830 fallback, ok := f.addr(addr) 831 if !ok { 832 panic(fmt.Sprintf("unable to locate variable associated with address %v", addr)) 833 } 834 fallback = f.getElementPtr(fallback, 0) 835 v = f.cur.NewLoad(fallback) 836 if typ, ok := v.Type().(*types.PointerType); ok { 837 if sig := typ.ElemType.(*types.FuncType); ok { 838 // TODO: Figure out how to recover calling convention. 839 // Perhaps through context.json at call sites? 840 return v, sig, enum.CallingConvNone, true 841 } 842 } 843 panic(fmt.Errorf("invalid callee type; expected pointer to function type, got %v", v.Type())) 844 } 845 } 846 } 847 } 848 849 dbg.Printf("unable to locate function for argument %v of instruction at address %v\n", arg.Arg, arg.Parent.Addr) 850 switch a := arg.Arg.(type) { 851 case x86asm.Rel: 852 next := arg.Parent.Addr + bin.Address(arg.Parent.Len) 853 addr := next + bin.Address(a) 854 dbg.Println(" addr:", addr) 855 case x86asm.Mem: 856 addr := bin.Address(a.Disp) 857 dbg.Println(" addr:", addr) 858 } 859 panic("not yet implemented") 860 } 861 862 // redefEDX_EAX redefines the 64-bit pseudo-register EDX:EAX based on the value 863 // of EAX and EDX. 864 func (f *Func) redefEDX_EAX() { 865 if !f.usesEDX_EAX { 866 return 867 } 868 edx := f.useReg(x86.EDX) 869 eax := f.useReg(x86.EAX) 870 tmp1 := f.cur.NewSExt(edx, types.I64) 871 tmp2 := f.cur.NewZExt(eax, types.I64) 872 tmp := f.cur.NewOr(tmp1, tmp2) 873 f.defReg(x86.EDX_EAX, tmp) 874 }