Fix PPC64 proccontrol library injection; TOC value could be wrong
[dyninst.git] / proccontrol / src / loadLibrary / codegen-ppc.C
1 // PPC code generation routines for library injection
2
3 #include "loadLibrary/codegen.h"
4 #include "common/h/arch-power.h"
5 #include <iostream>
6
7
8 using namespace Dyninst;
9 using namespace NS_power;
10 using namespace ProcControlAPI;
11 using namespace std;
12
13 // User code can use up to 228 bytes under the stack pointer;
14 // we skip past this so that we don't mess things up. 
15 #define STACKSKIP 228
16
17 bool Codegen::generateCallPPC32(Address addr, const std::vector<Address> &args) {
18    // PPC32 on Linux is basically the same thing as x86; we do indirect because
19    // we can
20
21    // First, arguments
22    unsigned reg = 3;
23    for (auto iter = args.begin(); iter != args.end(); ++iter) {
24       generatePPC32(*iter, reg);
25       reg++;      
26    }
27
28    // And the call. We're going indirect, r0 -> LR -> call
29    generatePPC32(addr, 0);
30
31    instruction mtlr(MTLR0raw);
32    copyInt(mtlr.asInt());
33
34    instruction brl(BRLraw);
35    copyInt(brl.asInt());
36    return true;
37 }
38
39 bool Codegen::generateCallPPC64(Address addr, const std::vector<Address> &args) {
40    // PPC64 is a little more complicated, because we also need a TOC register value.
41    // That... is tricky. 
42
43    // First, arguments
44    unsigned reg = 3;
45    for (auto iter = args.begin(); iter != args.end(); ++iter) {
46       generatePPC64(*iter, reg);
47       reg++;      
48    }
49
50    if (toc_[addr] == 0) return false;
51    generatePPC64(toc_[addr], 2);
52
53    generatePPC64(addr, 0);
54
55    instruction mtlr(MTLR0raw);
56    copyInt(mtlr.asInt());
57
58    instruction brl(BRLraw);
59    copyInt(brl.asInt());
60    return true;
61 }
62
63 void Codegen::generatePPC32(Address val, unsigned reg) {
64
65       instruction insn;
66       insn.clear();
67       DFORM_OP_SET(insn, CAUop);
68       DFORM_RT_SET(insn, reg);
69       DFORM_RA_SET(insn, 0);
70       DFORM_SI_SET(insn, BOT_HI(val));
71       copyInt(insn.asInt());
72
73       insn.clear();
74       DFORM_OP_SET(insn, ORILop);
75       DFORM_RT_SET(insn, reg);
76       DFORM_RA_SET(insn, reg);
77       DFORM_SI_SET(insn, BOT_LO(val));
78       copyInt(insn.asInt());
79 }
80
81 void Codegen::generatePPC64(Address val, unsigned reg) {
82    generatePPC32(val >> 32, reg);
83
84    instruction insn;
85    insn.clear();
86    int shift = 32;
87    MDFORM_OP_SET( insn, RLDop);
88    MDFORM_RS_SET( insn, reg);
89    MDFORM_RA_SET( insn, reg);
90    MDFORM_SH_SET( insn, shift % 32);
91    MDFORM_MB_SET( insn, (63-shift) % 32);
92    MDFORM_MB2_SET(insn, (63-shift) / 32);
93    MDFORM_XO_SET( insn, ICRxop);
94    MDFORM_SH2_SET(insn, shift / 32);
95    MDFORM_RC_SET( insn, 0);
96    copyInt(insn.asInt());
97
98    // Can't just reuse the 32-bit generate, since CAUop zeroes the high bits...
99    // Instead, use ORIU/ORIL
100
101    insn.clear();
102    DFORM_OP_SET(insn, ORIUop);
103    DFORM_RT_SET(insn, reg);
104    DFORM_RA_SET(insn, reg);
105    DFORM_SI_SET(insn, BOT_HI(val));
106    copyInt(insn.asInt());
107    
108    insn.clear();
109    DFORM_OP_SET(insn, ORILop);
110    DFORM_RT_SET(insn, reg);
111    DFORM_RA_SET(insn, reg);
112    DFORM_SI_SET(insn, BOT_LO(val));
113    copyInt(insn.asInt());
114
115 }
116
117 bool Codegen::generatePreamblePPC32() {
118   instruction insn;
119   insn.clear();
120
121   DFORM_OP_SET(insn, CALop);
122   DFORM_RT_SET(insn, 1);
123   DFORM_RA_SET(insn, 1);
124   DFORM_SI_SET(insn, -STACKSKIP);
125   copyInt(insn.asInt());
126
127   return true;
128 }
129
130 bool Codegen::generatePreamblePPC64() {
131   return generatePreamblePPC32();
132 }