CACAO
patcher.cpp
Go to the documentation of this file.
1 /* src/vm/jit/powerpc/patcher.cpp - PowerPC code patching functions
2 
3  Copyright (C) 1996-2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5  Copyright (C) 2008 Theobroma Systems Ltd.
6 
7  This file is part of CACAO.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2, or (at
12  your option) any later version.
13 
14  This program is distributed in the hope that it will be useful, but
15  WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  02110-1301, USA.
23 
24 */
25 
26 
27 #include "config.h"
28 
29 #include <cassert>
30 #include <stdint.h>
31 
32 #include "vm/types.hpp"
33 
34 #include "vm/jit/powerpc/md.hpp"
35 
36 #include "mm/memory.hpp"
37 
38 #include "native/native.hpp"
39 
40 #include "vm/jit/builtin.hpp"
41 #include "vm/class.hpp"
42 #include "vm/field.hpp"
43 #include "vm/initialize.hpp"
44 #include "vm/options.hpp"
45 #include "vm/references.hpp"
46 #include "vm/resolve.hpp"
47 
48 #include "vm/jit/asmpart.hpp"
49 #include "vm/jit/methodheader.hpp"
51 
52 
53 /* patcher_patch_code **********************************************************
54 
55  Just patches back the original machine code.
56 
57 *******************************************************************************/
58 
60 {
61  // Patch back original code.
62  *((uint32_t*) pr->mpc) = pr->mcode;
63 
64  // Synchronize instruction cache.
65  md_icacheflush((void*) pr->mpc, 1 * 4);
66 }
67 
68 
69 /**
70  * Check if the trap instruction at the given PC is valid.
71  *
72  * @param pc Program counter.
73  *
74  * @return true if valid, false otherwise.
75  */
77 {
78  uint32_t mcode = *((uint32_t*) pc);
79 
80  // Check for the undefined instruction we use.
81  return (mcode == 0x00000000);
82 }
83 
84 
85 /* patcher_resolve_classref_to_classinfo ***************************************
86 
87  ACONST:
88 
89  <patched call postition>
90  806dffc4 lwz r3,-60(r13)
91  81adffc0 lwz r13,-64(r13)
92  7da903a6 mtctr r13
93  4e800421 bctrl
94 
95 
96  MULTIANEWARRAY:
97 
98  <patched call position>
99  808dffc0 lwz r4,-64(r13)
100  38a10038 addi r5,r1,56
101  81adffbc lwz r13,-68(r13)
102  7da903a6 mtctr r13
103  4e800421 bctrl
104 
105 
106  ARRAYCHECKCAST:
107 
108  <patched call position>
109  808dffd8 lwz r4,-40(r13)
110  81adffd4 lwz r13,-44(r13)
111  7da903a6 mtctr r13
112  4e800421 bctrl
113 
114 *******************************************************************************/
115 
117 {
119  uintptr_t* datap = (uintptr_t*) pr->datap;
120 
121  // Resolve the class.
123 
124  if (c == NULL)
125  return false;
126 
127  // Patch the class pointer.
128  *datap = (uintptr_t) c;
129 
130  // Synchronize data cache.
131  md_dcacheflush(datap, SIZEOF_VOID_P);
132 
133  // Patch back the original code.
134  patcher_patch_code(pr);
135 
136  return true;
137 }
138 
139 
140 /* patcher_resolve_classref_to_vftbl *******************************************
141 
142  CHECKCAST (class):
143 
144  <patched call position>
145  81870000 lwz r12,0(r7)
146  800c0014 lwz r0,20(r12)
147  818dff78 lwz r12,-136(r13)
148 
149 
150  INSTANCEOF (class):
151 
152  <patched call position>
153  817d0000 lwz r11,0(r29)
154  818dff8c lwz r12,-116(r13)
155 
156 *******************************************************************************/
157 
159 {
161  uintptr_t* datap = (uintptr_t*) pr->datap;
162 
163  // Resolve the class.
165 
166  if (c == NULL)
167  return false;
168 
169  // Patch super class' vftbl.
170  *datap = (uintptr_t) c->vftbl;
171 
172  // Synchronize data cache.
173  md_dcacheflush(datap, SIZEOF_VOID_P);
174 
175  // Patch back the original code.
176  patcher_patch_code(pr);
177 
178  return true;
179 }
180 
181 
182 /* patcher_resolve_classref_to_flags *******************************************
183 
184  CHECKCAST/INSTANCEOF:
185 
186  <patched call position>
187  818dff7c lwz r12,-132(r13)
188 
189 *******************************************************************************/
190 
192 {
194  int32_t* datap = (int32_t*) pr->datap;
195 
196  // Resolve the class.
198 
199  if (c == NULL)
200  return false;
201 
202  // Patch class flags.
203  *datap = c->flags;
204 
205  // Synchronize data cache.
206  md_dcacheflush(datap, SIZEOF_VOID_P);
207 
208  // Patch back the original code.
209  patcher_patch_code(pr);
210 
211  return true;
212 }
213 
214 
215 /* patcher_get_putstatic *******************************************************
216 
217  Machine code:
218 
219  <patched call position>
220  816dffc8 lwz r11,-56(r13)
221  80ab0000 lwz r5,0(r11)
222 
223 *******************************************************************************/
224 
226 {
228  uintptr_t* datap = (uintptr_t*) pr->datap;
229 
230  // Resolve the field.
231  fieldinfo* fi = resolve_field_eager(uf);
232 
233  if (fi == NULL)
234  return false;
235 
236  // Check if the field's class is initialized.
237  if (!(fi->clazz->state & CLASS_INITIALIZED))
238  if (!initialize_class(fi->clazz))
239  return false;
240 
241  // Patch the field value's address.
242  *datap = (uintptr_t) fi->value;
243 
244  // Synchronize data cache.
245  md_dcacheflush(datap, SIZEOF_VOID_P);
246 
247  // Patch back the original code.
248  patcher_patch_code(pr);
249 
250  return true;
251 }
252 
253 
254 /* patcher_get_putfield ********************************************************
255 
256  Machine code:
257 
258  <patched call position>
259  811f0014 lwz r8,20(r31)
260 
261 *******************************************************************************/
262 
264 {
265  uint32_t* pc = (uint32_t*) pr->mpc;
267 
268  // Resolve the field.
269  fieldinfo* fi = resolve_field_eager(uf);
270 
271  if (fi == NULL)
272  return false;
273 
274  // Patch the field's offset.
275  if (IS_LNG_TYPE(fi->type)) {
276  /* If the field has type long, we have to patch two
277  instructions. But we have to check which instruction
278  is first. We do that with the offset of the first
279  instruction. */
280 
281  uint32_t disp = (pr->mcode & 0x0000ffff);
282 
283  if (disp == 4) {
284  pr->mcode &= 0xffff0000;
285  pr->mcode |= ((fi->offset + 4) & 0x0000ffff);
286  pc[1] |= ((fi->offset + 0) & 0x0000ffff);
287  }
288  else {
289  pr->mcode |= ((fi->offset + 0) & 0x0000ffff);
290  pc[1] &= 0xffff0000;
291  pc[1] |= ((fi->offset + 4) & 0x0000ffff);
292  }
293 
294  // Synchronize instruction cache.
295  md_icacheflush(pc + 1, 1 * 4);
296  }
297  else {
298  pr->mcode |= (fi->offset & 0x0000ffff);
299  }
300 
301  // Patch back the original code.
302  patcher_patch_code(pr);
303 
304  return true;
305 }
306 
307 
308 /* patcher_invokestatic_special ************************************************
309 
310  Machine code:
311 
312  <patched call position>
313  81adffd8 lwz r13,-40(r13)
314  7da903a6 mtctr r13
315  4e800421 bctrl
316 
317 ******************************************************************************/
318 
320 {
322  uintptr_t* datap = (uintptr_t*) pr->datap;
323 
324  // Resolve the method.
326 
327  if (m == NULL)
328  return false;
329 
330  // Patch stubroutine.
331  *datap = (uintptr_t) m->stubroutine;
332 
333  // Synchronize data cache.
334  md_dcacheflush(datap, SIZEOF_VOID_P);
335 
336  // Patch back the original code.
337  patcher_patch_code(pr);
338 
339  return true;
340 }
341 
342 
343 /* patcher_invokevirtual *******************************************************
344 
345  Machine code:
346 
347  <patched call position>
348  81830000 lwz r12,0(r3)
349  81ac0088 lwz r13,136(r12)
350  7da903a6 mtctr r13
351  4e800421 bctrl
352 
353 *******************************************************************************/
354 
356 {
357  uint32_t* pc = (uint32_t*) pr->mpc;
359 
360  // Resolve the method.
362 
363  if (m == NULL)
364  return false;
365 
366  // Patch vftbl index.
367  int32_t disp = (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex);
368 
369  pc[1] |= (disp & 0x0000ffff);
370 
371  // Synchronize instruction cache.
372  md_icacheflush(pc + 1, 1 * 4);
373 
374  // Patch back the original code.
375  patcher_patch_code(pr);
376 
377  return true;
378 }
379 
380 
381 /* patcher_invokeinterface *****************************************************
382 
383  Machine code:
384 
385  <patched call position>
386  81830000 lwz r12,0(r3)
387  818cffd0 lwz r12,-48(r12)
388  81ac000c lwz r13,12(r12)
389  7da903a6 mtctr r13
390  4e800421 bctrl
391 
392 *******************************************************************************/
393 
395 {
396  uint32_t* pc = (uint32_t*) pr->mpc;
398 
399  // Resolve the method.
401 
402  if (m == NULL)
403  return false;
404 
405  // Patch interfacetable index.
406  int32_t disp = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * m->clazz->index;
407 
408  /* XXX TWISTI: check displacement */
409  pc[1] |= (disp & 0x0000ffff);
410 
411  // Patch method offset.
412  disp = sizeof(methodptr) * (m - m->clazz->methods);
413 
414  /* XXX TWISTI: check displacement */
415  pc[2] |= (disp & 0x0000ffff);
416 
417  // Synchronize instruction cache.
418  md_icacheflush(pc + 1, 2 * 4);
419 
420  // Patch back the original code.
421  patcher_patch_code(pr);
422 
423  return true;
424 }
425 
426 
427 /* patcher_checkcast_interface *************************************************
428 
429  Machine code:
430 
431  <patched call position>
432  81870000 lwz r12,0(r7)
433  800c0010 lwz r0,16(r12)
434  34000000 addic. r0,r0,0
435  41810008 bgt- 0x014135d8
436  83c00003 lwz r30,3(0)
437  800c0000 lwz r0,0(r12)
438 
439 *******************************************************************************/
440 
442 {
443  uint32_t* pc = (uint32_t*) pr->mpc;
445 
446  // Resolve the class.
448 
449  if (c == NULL)
450  return false;
451 
452  // Patch super class index.
453  int32_t disp = -(c->index);
454  pc[2] |= (disp & 0x0000ffff);
455 
456  disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
457  pc[5] |= (disp & 0x0000ffff);
458 
459  // Synchronize instruction cache.
460  md_icacheflush(pc + 2, 4 * 4);
461 
462  // Patch back the original code.
463  patcher_patch_code(pr);
464 
465  return true;
466 }
467 
468 
469 /* patcher_instanceof_interface ************************************************
470 
471  Machine code:
472 
473  <patched call position>
474  81870000 lwz r12,0(r7)
475  800c0010 lwz r0,16(r12)
476  34000000 addic. r0,r0,0
477  41810008 bgt- 0x014135d8
478  83c00003 lwz r30,3(0)
479  800c0000 lwz r0,0(r12)
480 
481 *******************************************************************************/
482 
484 {
485  uint32_t* pc = (uint32_t*) pr->mpc;
487 
488  // Resolve the class.
490 
491  if (c == NULL)
492  return false;
493 
494  // Patch super class index.
495  int32_t disp = -(c->index);
496  pc[2] |= (disp & 0x0000ffff);
497 
498  disp = OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*);
499  pc[4] |= (disp & 0x0000ffff);
500 
501  // Synchronize instruction cache.
502  md_icacheflush(pc + 2, 3 * 4);
503 
504  // Patch back the original code.
505  patcher_patch_code(pr);
506 
507  return true;
508 }
509 
510 
511 /*
512  * These are local overrides for various environment variables in Emacs.
513  * Please do not remove this and leave it at the end of the file, where
514  * Emacs will automagically detect them.
515  * ---------------------------------------------------------------------
516  * Local variables:
517  * mode: c++
518  * indent-tabs-mode: t
519  * c-basic-offset: 4
520  * tab-width: 4
521  * End:
522  * vim:noexpandtab:sw=4:ts=4:
523  */
bool patcher_invokestatic_special(patchref_t *pr)
Definition: patcher.cpp:392
bool patcher_get_putstatic(patchref_t *pr)
Definition: patcher.cpp:264
bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
Definition: patcher.cpp:148
methodinfo * methods
Definition: class.hpp:113
bool patcher_invokeinterface(patchref_t *pr)
Definition: patcher.cpp:477
s4 state
Definition: class.hpp:115
static void md_dcacheflush(void *addr, int nbytes)
Definition: md.hpp:163
u1 * methodptr
Definition: global.hpp:40
u1 * stubroutine
Definition: method.hpp:102
s4 vftblindex
Definition: method.hpp:81
int32_t offset
Definition: field.hpp:66
classinfo * clazz
Definition: method.hpp:80
void patcher_patch_code(patchref_t *pr)
Definition: patcher.cpp:114
bool patcher_invokevirtual(patchref_t *pr)
Definition: patcher.cpp:433
imm_union * value
Definition: field.hpp:67
bool patcher_resolve_classref_to_flags(patchref_t *pr)
Definition: patcher.cpp:225
bool patcher_checkcast_interface(patchref_t *pr)
Definition: patcher.cpp:526
s4 flags
Definition: class.hpp:90
classinfo * clazz
Definition: field.hpp:55
s4 index
Definition: class.hpp:116
bool initialize_class(classinfo *c)
Definition: initialize.cpp:110
bool patcher_get_putfield(patchref_t *pr)
Definition: patcher.cpp:308
#define IS_LNG_TYPE(a)
Definition: global.hpp:135
vftbl_t * vftbl
Definition: class.hpp:121
fieldinfo * resolve_field_eager(unresolved_field *ref)
Definition: resolve.cpp:1497
#define pc
Definition: md-asm.hpp:56
s4 type
Definition: field.hpp:60
methodinfo * resolve_method_eager(unresolved_method *ref)
Definition: resolve.cpp:2236
uintptr_t datap
uint32_t mcode
classinfo * resolve_classref_eager(constant_classref *ref)
Definition: resolve.cpp:961
static void md_icacheflush(void *addr, int nbytes)
Definition: md.hpp:151
uintptr_t mpc
bool patcher_is_valid_trap_instruction_at(void *pc)
Check if the trap instruction at the given PC is valid.
Definition: patcher.cpp:72
#define OFFSET(s, el)
Definition: memory.hpp:90
bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
Definition: patcher.cpp:188
bool patcher_instanceof_interface(patchref_t *pr)
Definition: patcher.cpp:572