Fix PPC64 proccontrol library injection; TOC value could be wrong
[dyninst.git] / proccontrol / src / loadLibrary / codegen.C
1 // Platform-independent code generation methods; mainly function
2 // lookup
3
4 #include "loadLibrary/codegen.h"
5 #include <iostream>
6 #include "int_process.h"
7
8 using namespace Dyninst;
9 using namespace ProcControlAPI;
10 using namespace std;
11
12
13 Codegen::Codegen(Process *proc, std::string libname) 
14    : proc_(proc), libname_(libname), codeStart_(0) {}
15
16 Codegen::~Codegen() {
17    int_process *llproc = proc_->llproc();
18    if (codeStart_ && llproc) {
19       llproc->infFree(buffer_.startAddr());
20    }
21 }
22
23 bool Codegen::generate() {
24    unsigned size = estimateSize();
25    int_process *proc = proc_->llproc();
26    if (!proc)
27       return false;
28    
29    codeStart_ = proc->infMalloc(size, false, (unsigned int) 0);
30    if (!codeStart_) {
31       return false;
32    }
33
34    buffer_.initialize(codeStart_, size);
35
36    if (!generateInt()) return false;
37
38    generateTrap();
39    generateTrap();
40
41    assert(buffer_.size() <= size);
42
43    return true;
44 }
45
46 unsigned Codegen::startOffset() const {
47    return codeStart_ - buffer_.startAddr();
48 }
49
50 unsigned Codegen::estimateSize() {
51    // Major overestimation...
52    return 256 + libname_.length();
53 }
54
55 Address Codegen::findSymbolAddr(const std::string name, bool saveTOC) {
56    LibraryPool& libs = proc_->libraries();
57    for (auto li = libs.begin(); li != libs.end(); li++) {
58       if ((*li)->getName().empty()) continue;
59
60       SymReader *objSymReader = proc_->llproc()->getSymReader()->openSymbolReader((*li)->getName());
61       if (!objSymReader) continue;
62       
63       Symbol_t lookupSym = objSymReader->getSymbolByName(name);
64       if (!objSymReader->isValidSymbol(lookupSym)) continue;
65
66       Address addr = (*li)->getLoadAddress() + objSymReader->getSymbolOffset(lookupSym);
67
68       if (saveTOC) {
69          toc_[addr] = (*li)->getLoadAddress() + objSymReader->getSymbolTOC(lookupSym);
70       }
71       return addr;
72    }
73    return 0;
74 }
75  
76 Address Codegen::copyString(std::string name) {
77    Address ret = buffer_.curAddr();
78    unsigned strsize = name.length() + 1;
79    // Round to multiple of 4
80    strsize += 3; strsize -= (strsize % 4);
81    buffer_.copy(name.begin(), name.end());
82    for (unsigned i = 0; i < (strsize - name.length()); ++i) {
83       buffer_.push_back((unsigned char) 0x0);
84    }
85    return ret;
86 }
87
88 Address Codegen::copyBuf(void *buf, unsigned size) {
89    Address ret = buffer_.curAddr();
90    // Round size to multiple of 4
91    size += 3; size -= (size % 4);
92    buffer_.copy(buf, size);
93    return ret;
94 }
95
96 Address Codegen::copyByte(unsigned char c) {
97    Address ret = buffer_.curAddr();
98    buffer_.push_back(c);
99    return ret;
100 }
101
102 Address Codegen::copyInt(unsigned int i) {
103    Address ret = buffer_.curAddr();
104    buffer_.push_back(i);
105    return ret;
106 }
107
108 Address Codegen::copyLong(unsigned long l) {
109    Address ret = buffer_.curAddr();
110    buffer_.push_back(l);
111    return ret;
112 }
113
114 bool Codegen::generateCall(Address addr, const std::vector<Address> &args) {
115    switch (proc_->getArchitecture()) {
116       case Arch_x86:
117          return generateCallIA32(addr, args);
118       case Arch_x86_64:
119          return generateCallAMD64(addr, args);
120       case Arch_ppc32:
121          return generateCallPPC32(addr, args);
122       case Arch_ppc64:
123          return generateCallPPC64(addr, args);
124       default:
125          return false;
126    }
127 }
128
129 bool Codegen::generateNoops() {
130    // Linux has an annoying habit of rewinding the PC before executing code
131    // if you're in a system call; so 8-byte pad no matter what. 
132    switch(proc_->getArchitecture()) {
133       case Arch_x86:
134       case Arch_x86_64:
135          copyInt(0x90909090);
136          copyInt(0x90909090);
137          break;
138       case Arch_ppc32:
139       case Arch_ppc64:
140          copyInt(0x60000000);
141          copyInt(0x60000000);
142          break;
143       default:
144          return false;
145          break;
146    }
147    return true;
148 }
149
150 bool Codegen::generateTrap() {
151    switch(proc_->getArchitecture()) {
152       case Arch_x86:
153       case Arch_x86_64:
154          copyByte(0xcc);
155          break;
156       case Arch_ppc32:
157       case Arch_ppc64:
158          copyInt(0x7d821008);
159          break;
160       default:
161          return false;
162          break;
163    }
164    return true;
165 }
166
167
168 bool Codegen::generatePreamble() {
169    switch (proc_->getArchitecture()) {
170       case Arch_x86:
171          return generatePreambleIA32();
172       case Arch_x86_64:
173          return generatePreambleAMD64();
174       case Arch_ppc32:
175          return generatePreamblePPC32();
176       case Arch_ppc64:
177          return generatePreamblePPC64();
178       default:
179          return false;
180    }
181 }