CACAO
md.cpp
Go to the documentation of this file.
1 /* src/vm/jit/arm/md.cpp - machine dependent ARM functions
2 
3  Copyright (C) 1996-2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5  Copyright (C) 2009 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/jit/arm/codegen.hpp"
33 #include "vm/jit/arm/md.hpp"
34 #include "vm/jit/arm/md-abi.hpp"
35 
38 #include "vm/jit/trap.hpp"
39 
40 
41 /* md_init *********************************************************************
42 
43  Do some machine dependent initialization.
44 
45 *******************************************************************************/
46 
47 void md_init(void)
48 {
49  /* do nothing here */
50 }
51 
52 
53 /* md_jit_method_patch_address *************************************************
54 
55  Gets the patch address of the currently compiled method. The offset
56  is extracted from the load instruction(s) before the jump and added
57  to the right base address (PV or REG_METHODPTR).
58 
59  Machine code:
60 
61  e51cc040 ldr ip, [ip, #-64]
62  e1a0e00f mov lr, pc
63  e1a0f00c mov pc, ip
64 
65  or
66 
67  e590b000 ldr fp, [r0]
68  e59bc004 ldr ip, [fp, #4]
69  e1a0e00f mov lr, pc
70  e1a0f00c mov pc, ip
71 
72  or
73 
74  e590b000 ldr fp, [r0]
75  e28bca01 add ip, fp, #4096 ; 0x1000
76  e59cc004 ldr ip, [ip, #4]
77  e1a0e00f mov lr, pc
78  e1a0f00c mov pc, ip
79 
80  How we find out the patching address to store new method pointer:
81  - loaded IP with LDR IP,[METHODPTR]?
82  yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!)
83  - loaded IP from data segment
84  yes=INVOKESTATIC or INVOKESPECIAL (things are complicated)
85  recompute pointer to data segment, maybe larger offset
86 
87 *******************************************************************************/
88 
89 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
90 {
91  uint32_t *pc;
92  uint32_t mcode;
93  int32_t disp;
94  void *pa; /* patch address */
95 
96  /* Go back to the actual load instruction. */
97 
98  pc = ((uint32_t *) ra) - 3;
99 
100  /* Get first instruction word on current PC. */
101 
102  mcode = pc[0];
103 
104  /* Sanity check: Are we inside jit code? */
105 
106  assert(pc[1] == 0xe1a0e00f /*MOV LR,PC*/);
107  assert(pc[2] == 0xe1a0f00c /*MOV PC,IP*/);
108 
109  /* Sanity check: We unconditionally loaded a word into REG_PV? */
110 
111  assert ((mcode & 0xff70f000) == 0xe510c000);
112 
113  /* Get load displacement. */
114 
115  disp = (int32_t) (mcode & 0x0fff);
116 
117  /* Case: We loaded from base REG_PV with negative displacement. */
118 
119  if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0) {
120  /* We loaded from data segment, displacement can be larger. */
121 
122  mcode = pc[-1];
123 
124  /* check for "SUB IP, IP, #??, ROTL 12" */
125 
126  if ((mcode & 0xffffff00) == 0xe24cca00)
127  disp += (int32_t) ((mcode & 0x00ff) << 12);
128 
129  /* and get the final data segment address */
130 
131  pa = ((uint8_t *) pv) - disp;
132  }
133 
134  /* Case: We loaded from base REG_METHODPTR with positive displacement. */
135 
136  else if (M_MEM_GET_Rbase(mcode) == REG_METHODPTR && (mcode & 0x00800000) == 0x00800000) {
137  /* return NULL if no mptr was specified (used for replacement) */
138 
139  if (mptr == NULL)
140  return NULL;
141 
142  /* we loaded from REG_METHODPTR */
143 
144  pa = ((uint8_t *) mptr) + disp;
145  }
146 
147  /* Case: We loaded from base REG_PV with positive offset. */
148 
149  else if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0x00800000) {
150  /* We loaded with a larger displacement. Normally this means we loaded
151  from REG_METHODPTR. However there is a corner case if we loaded
152  from the data segment at an address aligned to 12 bit, which leads to a
153  zero (positive) displacement for the last instruction. */
154 
155  mcode = pc[-1];
156 
157  /* check for "ADD IP, FP, #??, ROTL 12" */
158 
159  if ((mcode & 0xffffff00) == 0xe28bca00) {
160  /* We loaded from REG_METHODPTR with a larger displacement. */
161 
162  assert(mptr != NULL);
163  disp += (int32_t) ((mcode & 0x00ff) << 12);
164  pa = ((uint8_t *) mptr) + disp;
165  }
166 
167  /* check for "SUB IP, IP, #??, ROTL 12" (corner case) */
168 
169  else if ((mcode & 0xffffff00) == 0xe24cca00 && disp == 0) {
170  /* We loaded from data segment with a larger displacement aligned to 12 bit. */
171 
172  disp += (int32_t) ((mcode & 0x00ff) << 12);
173  pa = ((uint8_t *) pv) - disp;
174  }
175 
176  /* Case is not covered, something is severely wrong. */
177 
178  else {
179  vm_abort_disassemble(pc - 1, 4, "md_jit_method_patch_address: unknown instruction %x", mcode);
180 
181  /* Keep compiler happy. */
182 
183  pa = NULL;
184  }
185  }
186 
187  /* Case is not covered, something is severely wrong. */
188 
189  else {
190  vm_abort_disassemble(pc, 3, "md_jit_method_patch_address: unknown instruction %x", mcode);
191 
192  /* Keep compiler happy. */
193 
194  pa = NULL;
195  }
196 
197  return pa;
198 }
199 
200 
201 /**
202  * Decode the trap instruction at the given PC.
203  *
204  * @param trp information about trap to be filled
205  * @param sig signal number
206  * @param xpc exception PC
207  * @param es execution state of the machine
208  * @return true if trap was decoded successfully, false otherwise.
209  */
210 bool md_trap_decode(trapinfo_t* trp, int sig, void* xpc, executionstate_t* es)
211 {
212  // Get the exception-throwing instruction.
213  uint32_t mcode = *((uint32_t*) xpc);
214 
215  switch (sig) {
216  case TRAP_SIGILL:
217  // Check for valid trap instruction.
219  trp->type = (mcode >> 8) & 0x0fff;
220  trp->value = es->intregs[mcode & 0x0f];
221  return true;
222  }
223  return false;
224 
225  case TRAP_SIGSEGV:
226  {
227  // Sanity check for load/store instruction.
228  // FIXME Implement this!
229 
230  // Retrieve base address of load/store instruction.
231  uintptr_t addr = es->intregs[(mcode >> 16) & 0x0f];
232 
233  // Check for implicit NullPointerException.
234  if (addr == 0) {
236  trp->value = 0;
237  return true;
238  }
239  }
240 
241  default:
242  return false;
243  }
244 }
245 
246 
247 /**
248  * Patch the given replacement point.
249  */
250 #if defined(ENABLE_REPLACEMENT)
251 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
252 {
253  vm_abort("md_patch_replacement_point: IMPLEMENT ME!");
254 }
255 #endif
256 
257 
258 /*
259  * These are local overrides for various environment variables in Emacs.
260  * Please do not remove this and leave it at the end of the file, where
261  * Emacs will automagically detect them.
262  * ---------------------------------------------------------------------
263  * Local variables:
264  * mode: c++
265  * indent-tabs-mode: t
266  * c-basic-offset: 4
267  * tab-width: 4
268  * End:
269  * vim:noexpandtab:sw=4:ts=4:
270  */
#define pv
Definition: md-asm.hpp:65
#define REG_PV
Definition: md-abi.hpp:42
intptr_t value
Value (numeric or address) passed with the trap.
Definition: trap.hpp:44
#define mptr
Definition: md-asm.hpp:66
#define ra
Definition: md-asm.hpp:62
Contains information about a decoded trap instruction.
Definition: trap.hpp:42
uint8_t u1
Definition: types.hpp:40
void vm_abort(const char *text,...)
Definition: vm.cpp:2586
#define xpc
Definition: md-asm.hpp:51
int type
Specific trap type (see md-trap.h).
Definition: trap.hpp:43
#define M_MEM_GET_Rbase(mcode)
Definition: codegen.hpp:183
void * md_jit_method_patch_address(void *pv, void *ra, void *mptr)
Definition: md.cpp:83
#define pc
Definition: md-asm.hpp:56
bool md_trap_decode(trapinfo_t *trp, int sig, void *xpc, executionstate_t *es)
Decode the trap instruction at the given PC.
Definition: md.cpp:192
#define REG_METHODPTR
Definition: md-abi.hpp:43
uintptr_t intregs[INT_REG_CNT]
void vm_abort_disassemble(void *pc, int count, const char *text,...)
Definition: vm.cpp:2001
void md_init(void)
Definition: md.cpp:48
bool patcher_is_valid_trap_instruction_at(void *pc)
Check if the trap instruction at the given PC is valid.
Definition: patcher.cpp:72