author | ohair |
Wed, 08 Jul 2009 09:12:17 -0700 | |
changeset 3223 | 24e98ad0c62e |
parent 3067 | 503964947e9f |
child 3288 | db82a42da273 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
2 |
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. |
|
3 |
* |
|
4 |
* Redistribution and use in source and binary forms, with or without |
|
5 |
* modification, are permitted provided that the following conditions |
|
6 |
* are met: |
|
7 |
* |
|
8 |
* - Redistributions of source code must retain the above copyright |
|
9 |
* notice, this list of conditions and the following disclaimer. |
|
10 |
* |
|
11 |
* - Redistributions in binary form must reproduce the above copyright |
|
12 |
* notice, this list of conditions and the following disclaimer in the |
|
13 |
* documentation and/or other materials provided with the distribution. |
|
14 |
* |
|
15 |
* - Neither the name of Sun Microsystems nor the names of its |
|
16 |
* contributors may be used to endorse or promote products derived |
|
17 |
* from this software without specific prior written permission. |
|
18 |
* |
|
19 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
|
20 |
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
21 |
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
22 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
23 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
24 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
25 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
26 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
27 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
28 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
29 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
30 |
*/ |
|
31 |
||
32 |
/* Class reader writer (java_crw_demo) for instrumenting bytecodes */ |
|
33 |
||
34 |
/* |
|
35 |
* As long as the callbacks allow for it and the class number is unique, |
|
36 |
* this code is completely re-entrant and any number of classfile |
|
37 |
* injections can happen at the same time. |
|
38 |
* |
|
39 |
* The current logic requires a unique number for this class instance |
|
40 |
* or (jclass,jobject loader) pair, this is done via the ClassIndex |
|
41 |
* in hprof, which is passed in as the 'unsigned cnum' to java_crw_demo(). |
|
42 |
* It's up to the user of this interface if it wants to use this |
|
43 |
* feature. |
|
44 |
* |
|
45 |
*/ |
|
46 |
||
47 |
#include <stdio.h> |
|
48 |
#include <stdlib.h> |
|
49 |
#include <string.h> |
|
50 |
||
51 |
/* Get Java and class file and bytecode information. */ |
|
52 |
||
53 |
#include <jni.h> |
|
54 |
||
55 |
#include "classfile_constants.h" |
|
56 |
||
57 |
||
58 |
/* Include our own interface for cross check */ |
|
59 |
||
60 |
#include "java_crw_demo.h" |
|
61 |
||
62 |
/* Macros over error functions to capture line numbers */ |
|
63 |
||
64 |
#define CRW_FATAL(ci, message) fatal_error(ci, message, __FILE__, __LINE__) |
|
65 |
||
66 |
#if defined(DEBUG) || !defined(NDEBUG) |
|
67 |
||
68 |
#define CRW_ASSERT(ci, cond) \ |
|
69 |
((cond)?(void)0:assert_error(ci, #cond, __FILE__, __LINE__)) |
|
70 |
||
71 |
#else |
|
72 |
||
73 |
#define CRW_ASSERT(ci, cond) |
|
74 |
||
75 |
#endif |
|
76 |
||
77 |
#define CRW_ASSERT_MI(mi) CRW_ASSERT((mi)?(mi)->ci:NULL,(mi)!=NULL) |
|
78 |
||
79 |
#define CRW_ASSERT_CI(ci) CRW_ASSERT(ci, ( (ci) != NULL && \ |
|
80 |
(ci)->input_position <= (ci)->input_len && \ |
|
81 |
(ci)->output_position <= (ci)->output_len) ) |
|
82 |
||
83 |
/* Typedefs for various integral numbers, just for code clarity */ |
|
84 |
||
85 |
typedef unsigned ClassOpcode; /* One opcode */ |
|
86 |
typedef unsigned char ByteCode; /* One byte from bytecodes */ |
|
87 |
typedef int ByteOffset; /* Byte offset */ |
|
88 |
typedef int ClassConstant; /* Constant pool kind */ |
|
89 |
typedef long CrwPosition; /* Position in class image */ |
|
90 |
typedef unsigned short CrwCpoolIndex; /* Index into constant pool */ |
|
91 |
||
92 |
/* Misc support macros */ |
|
93 |
||
94 |
/* Given the position of an opcode, find the next 4byte boundary position */ |
|
95 |
#define NEXT_4BYTE_BOUNDARY(opcode_pos) (((opcode_pos)+4) & (~3)) |
|
96 |
||
97 |
#define LARGEST_INJECTION (12*3) /* 3 injections at same site */ |
|
98 |
#define MAXIMUM_NEW_CPOOL_ENTRIES 64 /* don't add more than 32 entries */ |
|
99 |
||
100 |
/* Constant Pool Entry (internal table that mirrors pool in file image) */ |
|
101 |
||
102 |
typedef struct { |
|
103 |
const char * ptr; /* Pointer to any string */ |
|
104 |
unsigned short len; /* Length of string */ |
|
105 |
unsigned int index1; /* 1st 16 bit index or 32bit value. */ |
|
106 |
unsigned int index2; /* 2nd 16 bit index or 32bit value. */ |
|
107 |
ClassConstant tag; /* Tag or kind of entry. */ |
|
108 |
} CrwConstantPoolEntry; |
|
109 |
||
110 |
struct MethodImage; |
|
111 |
||
112 |
/* Class file image storage structure */ |
|
113 |
||
114 |
typedef struct CrwClassImage { |
|
115 |
||
116 |
/* Unique class number for this class */ |
|
117 |
unsigned number; |
|
118 |
||
119 |
/* Name of class, given or gotten out of class image */ |
|
120 |
const char * name; |
|
121 |
||
122 |
/* Input and Output class images tracking */ |
|
123 |
const unsigned char * input; |
|
124 |
unsigned char * output; |
|
125 |
CrwPosition input_len; |
|
126 |
CrwPosition output_len; |
|
127 |
CrwPosition input_position; |
|
128 |
CrwPosition output_position; |
|
129 |
||
130 |
/* Mirrored constant pool */ |
|
131 |
CrwConstantPoolEntry * cpool; |
|
132 |
CrwCpoolIndex cpool_max_elements; /* Max count */ |
|
133 |
CrwCpoolIndex cpool_count_plus_one; |
|
134 |
||
135 |
/* Input flags about class (e.g. is it a system class) */ |
|
136 |
int system_class; |
|
137 |
||
138 |
/* Class access flags gotten from file. */ |
|
139 |
unsigned access_flags; |
|
140 |
||
141 |
/* Names of classes and methods. */ |
|
142 |
char* tclass_name; /* Name of class that has tracker methods. */ |
|
143 |
char* tclass_sig; /* Signature of class */ |
|
144 |
char* call_name; /* Method name to call at offset 0 */ |
|
145 |
char* call_sig; /* Signature of this method */ |
|
146 |
char* return_name; /* Method name to call before any return */ |
|
147 |
char* return_sig; /* Signature of this method */ |
|
148 |
char* obj_init_name; /* Method name to call in Object <init> */ |
|
149 |
char* obj_init_sig; /* Signature of this method */ |
|
150 |
char* newarray_name; /* Method name to call after newarray opcodes */ |
|
151 |
char* newarray_sig; /* Signature of this method */ |
|
152 |
||
153 |
/* Constant pool index values for new entries */ |
|
154 |
CrwCpoolIndex tracker_class_index; |
|
155 |
CrwCpoolIndex object_init_tracker_index; |
|
156 |
CrwCpoolIndex newarray_tracker_index; |
|
157 |
CrwCpoolIndex call_tracker_index; |
|
158 |
CrwCpoolIndex return_tracker_index; |
|
159 |
CrwCpoolIndex class_number_index; /* Class number in pool */ |
|
160 |
||
161 |
/* Count of injections made into this class */ |
|
162 |
int injection_count; |
|
163 |
||
164 |
/* This class must be the java.lang.Object class */ |
|
165 |
jboolean is_object_class; |
|
166 |
||
167 |
/* This class must be the java.lang.Thread class */ |
|
168 |
jboolean is_thread_class; |
|
169 |
||
170 |
/* Callback functions */ |
|
171 |
FatalErrorHandler fatal_error_handler; |
|
172 |
MethodNumberRegister mnum_callback; |
|
173 |
||
174 |
/* Table of method names and descr's */ |
|
175 |
int method_count; |
|
176 |
const char ** method_name; |
|
177 |
const char ** method_descr; |
|
178 |
struct MethodImage * current_mi; |
|
179 |
||
180 |
} CrwClassImage; |
|
181 |
||
182 |
/* Injection bytecodes (holds injected bytecodes for each code position) */ |
|
183 |
||
184 |
typedef struct { |
|
185 |
ByteCode * code; |
|
186 |
ByteOffset len; |
|
187 |
} Injection; |
|
188 |
||
189 |
/* Method transformation data (allocated/freed as each method is processed) */ |
|
190 |
||
191 |
typedef struct MethodImage { |
|
192 |
||
193 |
/* Back reference to Class image data. */ |
|
194 |
CrwClassImage * ci; |
|
195 |
||
196 |
/* Unique method number for this class. */ |
|
197 |
unsigned number; |
|
198 |
||
199 |
/* Method name and descr */ |
|
200 |
const char * name; |
|
201 |
const char * descr; |
|
202 |
||
203 |
/* Map of input bytecode offsets to output bytecode offsets */ |
|
204 |
ByteOffset * map; |
|
205 |
||
206 |
/* Bytecode injections for each input bytecode offset */ |
|
207 |
Injection * injections; |
|
208 |
||
209 |
/* Widening setting for each input bytecode offset */ |
|
210 |
signed char * widening; |
|
211 |
||
212 |
/* Length of original input bytecodes, and new bytecodes. */ |
|
213 |
ByteOffset code_len; |
|
214 |
ByteOffset new_code_len; |
|
215 |
||
216 |
/* Location in input where bytecodes are located. */ |
|
217 |
CrwPosition start_of_input_bytecodes; |
|
218 |
||
219 |
/* Original max_stack and new max stack */ |
|
220 |
unsigned max_stack; |
|
221 |
unsigned new_max_stack; |
|
222 |
||
223 |
jboolean object_init_method; |
|
224 |
jboolean skip_call_return_sites; |
|
225 |
||
226 |
/* Method access flags gotten from file. */ |
|
227 |
unsigned access_flags; |
|
228 |
||
229 |
} MethodImage; |
|
230 |
||
231 |
/* ----------------------------------------------------------------- */ |
|
232 |
/* General support functions (memory and error handling) */ |
|
233 |
||
234 |
static void |
|
235 |
fatal_error(CrwClassImage *ci, const char *message, const char *file, int line) |
|
236 |
{ |
|
237 |
if ( ci != NULL && ci->fatal_error_handler != NULL ) { |
|
238 |
(*ci->fatal_error_handler)(message, file, line); |
|
239 |
} else { |
|
240 |
/* Normal operation should NEVER reach here */ |
|
241 |
/* NO CRW FATAL ERROR HANDLER! */ |
|
242 |
(void)fprintf(stderr, "CRW: %s [%s:%d]\n", message, file, line); |
|
243 |
abort(); |
|
244 |
} |
|
245 |
} |
|
246 |
||
247 |
#if defined(DEBUG) || !defined(NDEBUG) |
|
248 |
static void |
|
249 |
assert_error(CrwClassImage *ci, const char *condition, |
|
250 |
const char *file, int line) |
|
251 |
{ |
|
252 |
char buf[512]; |
|
253 |
MethodImage *mi; |
|
254 |
ByteOffset byte_code_offset; |
|
255 |
||
256 |
mi = ci->current_mi; |
|
257 |
if ( mi != NULL ) { |
|
258 |
byte_code_offset = (ByteOffset)(mi->ci->input_position - mi->start_of_input_bytecodes); |
|
259 |
} else { |
|
260 |
byte_code_offset=-1; |
|
261 |
} |
|
262 |
||
263 |
(void)sprintf(buf, |
|
264 |
"CRW ASSERTION FAILURE: %s (%s:%s:%d)", |
|
265 |
condition, |
|
3223
24e98ad0c62e
6855551: java -Xrunhprof crashes when running with classes compiled with targed=7
ohair
parents:
3067
diff
changeset
|
266 |
ci->name==NULL?"?":ci->name, |
24e98ad0c62e
6855551: java -Xrunhprof crashes when running with classes compiled with targed=7
ohair
parents:
3067
diff
changeset
|
267 |
(mi==NULL||mi->name==NULL)?"?":mi->name, |
2 | 268 |
byte_code_offset); |
269 |
fatal_error(ci, buf, file, line); |
|
270 |
} |
|
271 |
#endif |
|
272 |
||
273 |
static void * |
|
274 |
allocate(CrwClassImage *ci, int nbytes) |
|
275 |
{ |
|
276 |
void * ptr; |
|
277 |
||
278 |
if ( nbytes <= 0 ) { |
|
279 |
CRW_FATAL(ci, "Cannot allocate <= 0 bytes"); |
|
280 |
} |
|
281 |
ptr = malloc(nbytes); |
|
282 |
if ( ptr == NULL ) { |
|
283 |
CRW_FATAL(ci, "Ran out of malloc memory"); |
|
284 |
} |
|
285 |
return ptr; |
|
286 |
} |
|
287 |
||
288 |
static void * |
|
289 |
reallocate(CrwClassImage *ci, void *optr, int nbytes) |
|
290 |
{ |
|
291 |
void * ptr; |
|
292 |
||
293 |
if ( optr == NULL ) { |
|
294 |
CRW_FATAL(ci, "Cannot deallocate NULL"); |
|
295 |
} |
|
296 |
if ( nbytes <= 0 ) { |
|
297 |
CRW_FATAL(ci, "Cannot reallocate <= 0 bytes"); |
|
298 |
} |
|
299 |
ptr = realloc(optr, nbytes); |
|
300 |
if ( ptr == NULL ) { |
|
301 |
CRW_FATAL(ci, "Ran out of malloc memory"); |
|
302 |
} |
|
303 |
return ptr; |
|
304 |
} |
|
305 |
||
306 |
static void * |
|
307 |
allocate_clean(CrwClassImage *ci, int nbytes) |
|
308 |
{ |
|
309 |
void * ptr; |
|
310 |
||
311 |
if ( nbytes <= 0 ) { |
|
312 |
CRW_FATAL(ci, "Cannot allocate <= 0 bytes"); |
|
313 |
} |
|
314 |
ptr = calloc(nbytes, 1); |
|
315 |
if ( ptr == NULL ) { |
|
316 |
CRW_FATAL(ci, "Ran out of malloc memory"); |
|
317 |
} |
|
318 |
return ptr; |
|
319 |
} |
|
320 |
||
321 |
static const char * |
|
322 |
duplicate(CrwClassImage *ci, const char *str, int len) |
|
323 |
{ |
|
324 |
char *copy; |
|
325 |
||
326 |
copy = (char*)allocate(ci, len+1); |
|
327 |
(void)memcpy(copy, str, len); |
|
328 |
copy[len] = 0; |
|
329 |
return (const char *)copy; |
|
330 |
} |
|
331 |
||
332 |
static void |
|
333 |
deallocate(CrwClassImage *ci, void *ptr) |
|
334 |
{ |
|
335 |
if ( ptr == NULL ) { |
|
336 |
CRW_FATAL(ci, "Cannot deallocate NULL"); |
|
337 |
} |
|
338 |
(void)free(ptr); |
|
339 |
} |
|
340 |
||
341 |
/* ----------------------------------------------------------------- */ |
|
342 |
/* Functions for reading/writing bytes to/from the class images */ |
|
343 |
||
344 |
static unsigned |
|
345 |
readU1(CrwClassImage *ci) |
|
346 |
{ |
|
347 |
CRW_ASSERT_CI(ci); |
|
348 |
return ((unsigned)(ci->input[ci->input_position++])) & 0xFF; |
|
349 |
} |
|
350 |
||
351 |
static unsigned |
|
352 |
readU2(CrwClassImage *ci) |
|
353 |
{ |
|
354 |
unsigned res; |
|
355 |
||
356 |
res = readU1(ci); |
|
357 |
return (res << 8) + readU1(ci); |
|
358 |
} |
|
359 |
||
360 |
static signed short |
|
361 |
readS2(CrwClassImage *ci) |
|
362 |
{ |
|
363 |
unsigned res; |
|
364 |
||
365 |
res = readU1(ci); |
|
366 |
return ((res << 8) + readU1(ci)) & 0xFFFF; |
|
367 |
} |
|
368 |
||
369 |
static unsigned |
|
370 |
readU4(CrwClassImage *ci) |
|
371 |
{ |
|
372 |
unsigned res; |
|
373 |
||
374 |
res = readU2(ci); |
|
375 |
return (res << 16) + readU2(ci); |
|
376 |
} |
|
377 |
||
378 |
static void |
|
379 |
writeU1(CrwClassImage *ci, unsigned val) /* Only writes out lower 8 bits */ |
|
380 |
{ |
|
381 |
CRW_ASSERT_CI(ci); |
|
382 |
if ( ci->output != NULL ) { |
|
383 |
ci->output[ci->output_position++] = val & 0xFF; |
|
384 |
} |
|
385 |
} |
|
386 |
||
387 |
static void |
|
388 |
writeU2(CrwClassImage *ci, unsigned val) |
|
389 |
{ |
|
390 |
writeU1(ci, val >> 8); |
|
391 |
writeU1(ci, val); |
|
392 |
} |
|
393 |
||
394 |
static void |
|
395 |
writeU4(CrwClassImage *ci, unsigned val) |
|
396 |
{ |
|
397 |
writeU2(ci, val >> 16); |
|
398 |
writeU2(ci, val); |
|
399 |
} |
|
400 |
||
401 |
static unsigned |
|
402 |
copyU1(CrwClassImage *ci) |
|
403 |
{ |
|
404 |
unsigned value; |
|
405 |
||
406 |
value = readU1(ci); |
|
407 |
writeU1(ci, value); |
|
408 |
return value; |
|
409 |
} |
|
410 |
||
411 |
static unsigned |
|
412 |
copyU2(CrwClassImage *ci) |
|
413 |
{ |
|
414 |
unsigned value; |
|
415 |
||
416 |
value = readU2(ci); |
|
417 |
writeU2(ci, value); |
|
418 |
return value; |
|
419 |
} |
|
420 |
||
421 |
static unsigned |
|
422 |
copyU4(CrwClassImage *ci) |
|
423 |
{ |
|
424 |
unsigned value; |
|
425 |
||
426 |
value = readU4(ci); |
|
427 |
writeU4(ci, value); |
|
428 |
return value; |
|
429 |
} |
|
430 |
||
431 |
static void |
|
432 |
copy(CrwClassImage *ci, unsigned count) |
|
433 |
{ |
|
434 |
CRW_ASSERT_CI(ci); |
|
435 |
if ( ci->output != NULL ) { |
|
436 |
(void)memcpy(ci->output+ci->output_position, |
|
437 |
ci->input+ci->input_position, count); |
|
438 |
ci->output_position += count; |
|
439 |
} |
|
440 |
ci->input_position += count; |
|
441 |
CRW_ASSERT_CI(ci); |
|
442 |
} |
|
443 |
||
444 |
static void |
|
445 |
skip(CrwClassImage *ci, unsigned count) |
|
446 |
{ |
|
447 |
CRW_ASSERT_CI(ci); |
|
448 |
ci->input_position += count; |
|
449 |
} |
|
450 |
||
451 |
static void |
|
452 |
read_bytes(CrwClassImage *ci, void *bytes, unsigned count) |
|
453 |
{ |
|
454 |
CRW_ASSERT_CI(ci); |
|
455 |
CRW_ASSERT(ci, bytes!=NULL); |
|
456 |
(void)memcpy(bytes, ci->input+ci->input_position, count); |
|
457 |
ci->input_position += count; |
|
458 |
} |
|
459 |
||
460 |
static void |
|
461 |
write_bytes(CrwClassImage *ci, void *bytes, unsigned count) |
|
462 |
{ |
|
463 |
CRW_ASSERT_CI(ci); |
|
464 |
CRW_ASSERT(ci, bytes!=NULL); |
|
465 |
if ( ci->output != NULL ) { |
|
466 |
(void)memcpy(ci->output+ci->output_position, bytes, count); |
|
467 |
ci->output_position += count; |
|
468 |
} |
|
469 |
} |
|
470 |
||
471 |
static void |
|
472 |
random_writeU2(CrwClassImage *ci, CrwPosition pos, unsigned val) |
|
473 |
{ |
|
474 |
CrwPosition save_position; |
|
475 |
||
476 |
CRW_ASSERT_CI(ci); |
|
477 |
save_position = ci->output_position; |
|
478 |
ci->output_position = pos; |
|
479 |
writeU2(ci, val); |
|
480 |
ci->output_position = save_position; |
|
481 |
} |
|
482 |
||
483 |
static void |
|
484 |
random_writeU4(CrwClassImage *ci, CrwPosition pos, unsigned val) |
|
485 |
{ |
|
486 |
CrwPosition save_position; |
|
487 |
||
488 |
CRW_ASSERT_CI(ci); |
|
489 |
save_position = ci->output_position; |
|
490 |
ci->output_position = pos; |
|
491 |
writeU4(ci, val); |
|
492 |
ci->output_position = save_position; |
|
493 |
} |
|
494 |
||
495 |
/* ----------------------------------------------------------------- */ |
|
496 |
/* Constant Pool handling functions. */ |
|
497 |
||
498 |
static void |
|
499 |
fillin_cpool_entry(CrwClassImage *ci, CrwCpoolIndex i, |
|
500 |
ClassConstant tag, |
|
501 |
unsigned int index1, unsigned int index2, |
|
502 |
const char *ptr, int len) |
|
503 |
{ |
|
504 |
CRW_ASSERT_CI(ci); |
|
505 |
CRW_ASSERT(ci, i > 0 && i < ci->cpool_count_plus_one); |
|
506 |
ci->cpool[i].tag = tag; |
|
507 |
ci->cpool[i].index1 = index1; |
|
508 |
ci->cpool[i].index2 = index2; |
|
509 |
ci->cpool[i].ptr = ptr; |
|
510 |
ci->cpool[i].len = (unsigned short)len; |
|
511 |
} |
|
512 |
||
513 |
static CrwCpoolIndex |
|
514 |
add_new_cpool_entry(CrwClassImage *ci, ClassConstant tag, |
|
515 |
unsigned int index1, unsigned int index2, |
|
516 |
const char *str, int len) |
|
517 |
{ |
|
518 |
CrwCpoolIndex i; |
|
519 |
char *utf8 = NULL; |
|
520 |
||
521 |
CRW_ASSERT_CI(ci); |
|
522 |
i = ci->cpool_count_plus_one++; |
|
523 |
||
524 |
/* NOTE: This implementation does not automatically expand the |
|
525 |
* constant pool table beyond the expected number needed |
|
526 |
* to handle this particular CrwTrackerInterface injections. |
|
527 |
* See MAXIMUM_NEW_CPOOL_ENTRIES |
|
528 |
*/ |
|
529 |
CRW_ASSERT(ci, ci->cpool_count_plus_one < ci->cpool_max_elements ); |
|
530 |
||
531 |
writeU1(ci, tag); |
|
532 |
switch (tag) { |
|
533 |
case JVM_CONSTANT_Class: |
|
534 |
writeU2(ci, index1); |
|
535 |
break; |
|
536 |
case JVM_CONSTANT_String: |
|
537 |
writeU2(ci, index1); |
|
538 |
break; |
|
539 |
case JVM_CONSTANT_Fieldref: |
|
540 |
case JVM_CONSTANT_Methodref: |
|
541 |
case JVM_CONSTANT_InterfaceMethodref: |
|
542 |
case JVM_CONSTANT_Integer: |
|
543 |
case JVM_CONSTANT_Float: |
|
544 |
case JVM_CONSTANT_NameAndType: |
|
545 |
writeU2(ci, index1); |
|
546 |
writeU2(ci, index2); |
|
547 |
break; |
|
548 |
case JVM_CONSTANT_Long: |
|
549 |
case JVM_CONSTANT_Double: |
|
550 |
writeU4(ci, index1); |
|
551 |
writeU4(ci, index2); |
|
552 |
ci->cpool_count_plus_one++; |
|
553 |
CRW_ASSERT(ci, ci->cpool_count_plus_one < ci->cpool_max_elements ); |
|
554 |
break; |
|
555 |
case JVM_CONSTANT_Utf8: |
|
556 |
CRW_ASSERT(ci, len==(len & 0xFFFF)); |
|
557 |
writeU2(ci, len); |
|
558 |
write_bytes(ci, (void*)str, len); |
|
559 |
utf8 = (char*)duplicate(ci, str, len); |
|
560 |
break; |
|
561 |
default: |
|
562 |
CRW_FATAL(ci, "Unknown constant"); |
|
563 |
break; |
|
564 |
} |
|
565 |
fillin_cpool_entry(ci, i, tag, index1, index2, (const char *)utf8, len); |
|
566 |
CRW_ASSERT(ci, i > 0 && i < ci->cpool_count_plus_one); |
|
567 |
return i; |
|
568 |
} |
|
569 |
||
570 |
static CrwCpoolIndex |
|
571 |
add_new_class_cpool_entry(CrwClassImage *ci, const char *class_name) |
|
572 |
{ |
|
573 |
CrwCpoolIndex name_index; |
|
574 |
CrwCpoolIndex class_index; |
|
575 |
int len; |
|
576 |
||
577 |
CRW_ASSERT_CI(ci); |
|
578 |
CRW_ASSERT(ci, class_name!=NULL); |
|
579 |
||
580 |
len = (int)strlen(class_name); |
|
581 |
name_index = add_new_cpool_entry(ci, JVM_CONSTANT_Utf8, len, 0, |
|
582 |
class_name, len); |
|
583 |
class_index = add_new_cpool_entry(ci, JVM_CONSTANT_Class, name_index, 0, |
|
584 |
NULL, 0); |
|
585 |
return class_index; |
|
586 |
} |
|
587 |
||
588 |
static CrwCpoolIndex |
|
589 |
add_new_method_cpool_entry(CrwClassImage *ci, CrwCpoolIndex class_index, |
|
590 |
const char *name, const char *descr) |
|
591 |
{ |
|
592 |
CrwCpoolIndex name_index; |
|
593 |
CrwCpoolIndex descr_index; |
|
594 |
CrwCpoolIndex name_type_index; |
|
595 |
int len; |
|
596 |
||
597 |
CRW_ASSERT_CI(ci); |
|
598 |
CRW_ASSERT(ci, name!=NULL); |
|
599 |
CRW_ASSERT(ci, descr!=NULL); |
|
600 |
len = (int)strlen(name); |
|
601 |
name_index = |
|
602 |
add_new_cpool_entry(ci, JVM_CONSTANT_Utf8, len, 0, name, len); |
|
603 |
len = (int)strlen(descr); |
|
604 |
descr_index = |
|
605 |
add_new_cpool_entry(ci, JVM_CONSTANT_Utf8, len, 0, descr, len); |
|
606 |
name_type_index = |
|
607 |
add_new_cpool_entry(ci, JVM_CONSTANT_NameAndType, |
|
608 |
name_index, descr_index, NULL, 0); |
|
609 |
return add_new_cpool_entry(ci, JVM_CONSTANT_Methodref, |
|
610 |
class_index, name_type_index, NULL, 0); |
|
611 |
} |
|
612 |
||
613 |
static CrwConstantPoolEntry |
|
614 |
cpool_entry(CrwClassImage *ci, CrwCpoolIndex c_index) |
|
615 |
{ |
|
616 |
CRW_ASSERT_CI(ci); |
|
617 |
CRW_ASSERT(ci, c_index > 0 && c_index < ci->cpool_count_plus_one); |
|
618 |
return ci->cpool[c_index]; |
|
619 |
} |
|
620 |
||
621 |
static void |
|
622 |
cpool_setup(CrwClassImage *ci) |
|
623 |
{ |
|
624 |
CrwCpoolIndex i; |
|
625 |
CrwPosition cpool_output_position; |
|
626 |
int count_plus_one; |
|
627 |
||
628 |
CRW_ASSERT_CI(ci); |
|
629 |
cpool_output_position = ci->output_position; |
|
630 |
count_plus_one = copyU2(ci); |
|
631 |
CRW_ASSERT(ci, count_plus_one>1); |
|
632 |
ci->cpool_max_elements = count_plus_one+MAXIMUM_NEW_CPOOL_ENTRIES; |
|
633 |
ci->cpool = (CrwConstantPoolEntry*)allocate_clean(ci, |
|
634 |
(int)((ci->cpool_max_elements)*sizeof(CrwConstantPoolEntry))); |
|
635 |
ci->cpool_count_plus_one = (CrwCpoolIndex)count_plus_one; |
|
636 |
||
637 |
/* Index zero not in class file */ |
|
638 |
for (i = 1; i < count_plus_one; ++i) { |
|
639 |
CrwCpoolIndex ipos; |
|
640 |
ClassConstant tag; |
|
641 |
unsigned int index1; |
|
642 |
unsigned int index2; |
|
643 |
unsigned len; |
|
644 |
char * utf8; |
|
645 |
||
646 |
ipos = i; |
|
647 |
index1 = 0; |
|
648 |
index2 = 0; |
|
649 |
len = 0; |
|
650 |
utf8 = NULL; |
|
651 |
||
652 |
tag = copyU1(ci); |
|
653 |
switch (tag) { |
|
654 |
case JVM_CONSTANT_Class: |
|
655 |
index1 = copyU2(ci); |
|
656 |
break; |
|
657 |
case JVM_CONSTANT_String: |
|
658 |
index1 = copyU2(ci); |
|
659 |
break; |
|
660 |
case JVM_CONSTANT_Fieldref: |
|
661 |
case JVM_CONSTANT_Methodref: |
|
662 |
case JVM_CONSTANT_InterfaceMethodref: |
|
663 |
case JVM_CONSTANT_Integer: |
|
664 |
case JVM_CONSTANT_Float: |
|
665 |
case JVM_CONSTANT_NameAndType: |
|
666 |
index1 = copyU2(ci); |
|
667 |
index2 = copyU2(ci); |
|
668 |
break; |
|
669 |
case JVM_CONSTANT_Long: |
|
670 |
case JVM_CONSTANT_Double: |
|
671 |
index1 = copyU4(ci); |
|
672 |
index2 = copyU4(ci); |
|
673 |
++i; /* // these take two CP entries - duh! */ |
|
674 |
break; |
|
675 |
case JVM_CONSTANT_Utf8: |
|
676 |
len = copyU2(ci); |
|
677 |
index1 = (unsigned short)len; |
|
678 |
utf8 = (char*)allocate(ci, len+1); |
|
679 |
read_bytes(ci, (void*)utf8, len); |
|
680 |
utf8[len] = 0; |
|
681 |
write_bytes(ci, (void*)utf8, len); |
|
682 |
break; |
|
683 |
default: |
|
684 |
CRW_FATAL(ci, "Unknown constant"); |
|
685 |
break; |
|
686 |
} |
|
687 |
fillin_cpool_entry(ci, ipos, tag, index1, index2, (const char *)utf8, len); |
|
688 |
} |
|
689 |
||
690 |
if (ci->call_name != NULL || ci->return_name != NULL) { |
|
691 |
if ( ci->number != (ci->number & 0x7FFF) ) { |
|
692 |
ci->class_number_index = |
|
693 |
add_new_cpool_entry(ci, JVM_CONSTANT_Integer, |
|
694 |
(ci->number>>16) & 0xFFFF, ci->number & 0xFFFF, NULL, 0); |
|
695 |
} |
|
696 |
} |
|
697 |
||
698 |
if ( ci->tclass_name != NULL ) { |
|
699 |
ci->tracker_class_index = |
|
700 |
add_new_class_cpool_entry(ci, ci->tclass_name); |
|
701 |
} |
|
702 |
if (ci->obj_init_name != NULL) { |
|
703 |
ci->object_init_tracker_index = add_new_method_cpool_entry(ci, |
|
704 |
ci->tracker_class_index, |
|
705 |
ci->obj_init_name, |
|
706 |
ci->obj_init_sig); |
|
707 |
} |
|
708 |
if (ci->newarray_name != NULL) { |
|
709 |
ci->newarray_tracker_index = add_new_method_cpool_entry(ci, |
|
710 |
ci->tracker_class_index, |
|
711 |
ci->newarray_name, |
|
712 |
ci->newarray_sig); |
|
713 |
} |
|
714 |
if (ci->call_name != NULL) { |
|
715 |
ci->call_tracker_index = add_new_method_cpool_entry(ci, |
|
716 |
ci->tracker_class_index, |
|
717 |
ci->call_name, |
|
718 |
ci->call_sig); |
|
719 |
} |
|
720 |
if (ci->return_name != NULL) { |
|
721 |
ci->return_tracker_index = add_new_method_cpool_entry(ci, |
|
722 |
ci->tracker_class_index, |
|
723 |
ci->return_name, |
|
724 |
ci->return_sig); |
|
725 |
} |
|
726 |
||
727 |
random_writeU2(ci, cpool_output_position, ci->cpool_count_plus_one); |
|
728 |
} |
|
729 |
||
730 |
/* ----------------------------------------------------------------- */ |
|
731 |
/* Functions that create the bytecodes to inject */ |
|
732 |
||
733 |
static ByteOffset |
|
734 |
push_pool_constant_bytecodes(ByteCode *bytecodes, CrwCpoolIndex index) |
|
735 |
{ |
|
736 |
ByteOffset nbytes = 0; |
|
737 |
||
738 |
if ( index == (index&0x7F) ) { |
|
739 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_ldc; |
|
740 |
} else { |
|
741 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_ldc_w; |
|
742 |
bytecodes[nbytes++] = (ByteCode)((index >> 8) & 0xFF); |
|
743 |
} |
|
744 |
bytecodes[nbytes++] = (ByteCode)(index & 0xFF); |
|
745 |
return nbytes; |
|
746 |
} |
|
747 |
||
748 |
static ByteOffset |
|
749 |
push_short_constant_bytecodes(ByteCode *bytecodes, unsigned number) |
|
750 |
{ |
|
751 |
ByteOffset nbytes = 0; |
|
752 |
||
753 |
if ( number <= 5 ) { |
|
754 |
bytecodes[nbytes++] = (ByteCode)(JVM_OPC_iconst_0+number); |
|
755 |
} else if ( number == (number&0x7F) ) { |
|
756 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_bipush; |
|
757 |
bytecodes[nbytes++] = (ByteCode)(number & 0xFF); |
|
758 |
} else { |
|
759 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_sipush; |
|
760 |
bytecodes[nbytes++] = (ByteCode)((number >> 8) & 0xFF); |
|
761 |
bytecodes[nbytes++] = (ByteCode)(number & 0xFF); |
|
762 |
} |
|
763 |
return nbytes; |
|
764 |
} |
|
765 |
||
766 |
static ByteOffset |
|
767 |
injection_template(MethodImage *mi, ByteCode *bytecodes, ByteOffset max_nbytes, |
|
768 |
CrwCpoolIndex method_index) |
|
769 |
{ |
|
770 |
CrwClassImage * ci; |
|
771 |
ByteOffset nbytes = 0; |
|
772 |
unsigned max_stack; |
|
773 |
int add_dup; |
|
774 |
int add_aload; |
|
775 |
int push_cnum; |
|
776 |
int push_mnum; |
|
777 |
||
778 |
ci = mi->ci; |
|
779 |
||
780 |
CRW_ASSERT(ci, bytecodes!=NULL); |
|
781 |
||
782 |
if ( method_index == 0 ) { |
|
783 |
return 0; |
|
784 |
} |
|
785 |
||
786 |
if ( method_index == ci->newarray_tracker_index) { |
|
787 |
max_stack = mi->max_stack + 1; |
|
788 |
add_dup = JNI_TRUE; |
|
789 |
add_aload = JNI_FALSE; |
|
790 |
push_cnum = JNI_FALSE; |
|
791 |
push_mnum = JNI_FALSE; |
|
792 |
} else if ( method_index == ci->object_init_tracker_index) { |
|
793 |
max_stack = mi->max_stack + 1; |
|
794 |
add_dup = JNI_FALSE; |
|
795 |
add_aload = JNI_TRUE; |
|
796 |
push_cnum = JNI_FALSE; |
|
797 |
push_mnum = JNI_FALSE; |
|
798 |
} else { |
|
799 |
max_stack = mi->max_stack + 2; |
|
800 |
add_dup = JNI_FALSE; |
|
801 |
add_aload = JNI_FALSE; |
|
802 |
push_cnum = JNI_TRUE; |
|
803 |
push_mnum = JNI_TRUE; |
|
804 |
} |
|
805 |
||
806 |
if ( add_dup ) { |
|
807 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_dup; |
|
808 |
} |
|
809 |
if ( add_aload ) { |
|
810 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_aload_0; |
|
811 |
} |
|
812 |
if ( push_cnum ) { |
|
813 |
if ( ci->number == (ci->number & 0x7FFF) ) { |
|
814 |
nbytes += push_short_constant_bytecodes(bytecodes+nbytes, |
|
815 |
ci->number); |
|
816 |
} else { |
|
817 |
CRW_ASSERT(ci, ci->class_number_index!=0); |
|
818 |
nbytes += push_pool_constant_bytecodes(bytecodes+nbytes, |
|
819 |
ci->class_number_index); |
|
820 |
} |
|
821 |
} |
|
822 |
if ( push_mnum ) { |
|
823 |
nbytes += push_short_constant_bytecodes(bytecodes+nbytes, |
|
824 |
mi->number); |
|
825 |
} |
|
826 |
bytecodes[nbytes++] = (ByteCode)JVM_OPC_invokestatic; |
|
827 |
bytecodes[nbytes++] = (ByteCode)(method_index >> 8); |
|
828 |
bytecodes[nbytes++] = (ByteCode)method_index; |
|
829 |
bytecodes[nbytes] = 0; |
|
830 |
CRW_ASSERT(ci, nbytes<max_nbytes); |
|
831 |
||
832 |
/* Make sure the new max_stack is appropriate */ |
|
833 |
if ( max_stack > mi->new_max_stack ) { |
|
834 |
mi->new_max_stack = max_stack; |
|
835 |
} |
|
836 |
return nbytes; |
|
837 |
} |
|
838 |
||
839 |
/* Called to create injection code at entry to a method */ |
|
840 |
static ByteOffset |
|
841 |
entry_injection_code(MethodImage *mi, ByteCode *bytecodes, ByteOffset len) |
|
842 |
{ |
|
843 |
CrwClassImage * ci; |
|
844 |
ByteOffset nbytes = 0; |
|
845 |
||
846 |
CRW_ASSERT_MI(mi); |
|
847 |
||
848 |
ci = mi->ci; |
|
849 |
||
850 |
if ( mi->object_init_method ) { |
|
851 |
nbytes = injection_template(mi, |
|
852 |
bytecodes, len, ci->object_init_tracker_index); |
|
853 |
} |
|
854 |
if ( !mi->skip_call_return_sites ) { |
|
855 |
nbytes += injection_template(mi, |
|
856 |
bytecodes+nbytes, len-nbytes, ci->call_tracker_index); |
|
857 |
} |
|
858 |
return nbytes; |
|
859 |
} |
|
860 |
||
861 |
/* Called to create injection code before an opcode */ |
|
862 |
static ByteOffset |
|
863 |
before_injection_code(MethodImage *mi, ClassOpcode opcode, |
|
864 |
ByteCode *bytecodes, ByteOffset len) |
|
865 |
{ |
|
866 |
ByteOffset nbytes = 0; |
|
867 |
||
868 |
||
869 |
CRW_ASSERT_MI(mi); |
|
870 |
switch ( opcode ) { |
|
871 |
case JVM_OPC_return: |
|
872 |
case JVM_OPC_ireturn: |
|
873 |
case JVM_OPC_lreturn: |
|
874 |
case JVM_OPC_freturn: |
|
875 |
case JVM_OPC_dreturn: |
|
876 |
case JVM_OPC_areturn: |
|
877 |
if ( !mi->skip_call_return_sites ) { |
|
878 |
nbytes = injection_template(mi, |
|
879 |
bytecodes, len, mi->ci->return_tracker_index); |
|
880 |
} |
|
881 |
break; |
|
882 |
default: |
|
883 |
break; |
|
884 |
} |
|
885 |
return nbytes; |
|
886 |
} |
|
887 |
||
888 |
/* Called to create injection code after an opcode */ |
|
889 |
static ByteOffset |
|
890 |
after_injection_code(MethodImage *mi, ClassOpcode opcode, |
|
891 |
ByteCode *bytecodes, ByteOffset len) |
|
892 |
{ |
|
893 |
CrwClassImage* ci; |
|
894 |
ByteOffset nbytes; |
|
895 |
||
896 |
ci = mi->ci; |
|
897 |
nbytes = 0; |
|
898 |
||
899 |
CRW_ASSERT_MI(mi); |
|
900 |
switch ( opcode ) { |
|
901 |
case JVM_OPC_new: |
|
902 |
/* Can't inject here cannot pass around uninitialized object */ |
|
903 |
break; |
|
904 |
case JVM_OPC_newarray: |
|
905 |
case JVM_OPC_anewarray: |
|
906 |
case JVM_OPC_multianewarray: |
|
907 |
nbytes = injection_template(mi, |
|
908 |
bytecodes, len, ci->newarray_tracker_index); |
|
909 |
break; |
|
910 |
default: |
|
911 |
break; |
|
912 |
} |
|
913 |
return nbytes; |
|
914 |
} |
|
915 |
||
916 |
/* Actually inject the bytecodes */ |
|
917 |
static void |
|
918 |
inject_bytecodes(MethodImage *mi, ByteOffset at, |
|
919 |
ByteCode *bytecodes, ByteOffset len) |
|
920 |
{ |
|
921 |
Injection injection; |
|
922 |
CrwClassImage *ci; |
|
923 |
||
924 |
ci = mi->ci; |
|
925 |
CRW_ASSERT_MI(mi); |
|
926 |
CRW_ASSERT(ci, at <= mi->code_len); |
|
927 |
||
928 |
injection = mi->injections[at]; |
|
929 |
||
930 |
CRW_ASSERT(ci, len <= LARGEST_INJECTION/2); |
|
931 |
CRW_ASSERT(ci, injection.len+len <= LARGEST_INJECTION); |
|
932 |
||
933 |
/* Either start an injection area or concatenate to what is there */ |
|
934 |
if ( injection.code == NULL ) { |
|
935 |
CRW_ASSERT(ci, injection.len==0); |
|
936 |
injection.code = (ByteCode *)allocate_clean(ci, LARGEST_INJECTION+1); |
|
937 |
} |
|
938 |
||
939 |
(void)memcpy(injection.code+injection.len, bytecodes, len); |
|
940 |
injection.len += len; |
|
941 |
injection.code[injection.len] = 0; |
|
942 |
mi->injections[at] = injection; |
|
943 |
ci->injection_count++; |
|
944 |
} |
|
945 |
||
946 |
/* ----------------------------------------------------------------- */ |
|
947 |
/* Method handling functions */ |
|
948 |
||
949 |
static MethodImage * |
|
950 |
method_init(CrwClassImage *ci, unsigned mnum, ByteOffset code_len) |
|
951 |
{ |
|
952 |
MethodImage * mi; |
|
953 |
ByteOffset i; |
|
954 |
||
955 |
mi = (MethodImage*)allocate_clean(ci, (int)sizeof(MethodImage)); |
|
956 |
mi->ci = ci; |
|
957 |
mi->name = ci->method_name[mnum]; |
|
958 |
mi->descr = ci->method_descr[mnum]; |
|
959 |
mi->code_len = code_len; |
|
960 |
mi->map = (ByteOffset*)allocate_clean(ci, |
|
961 |
(int)((code_len+1)*sizeof(ByteOffset))); |
|
962 |
for(i=0; i<=code_len; i++) { |
|
963 |
mi->map[i] = i; |
|
964 |
} |
|
965 |
mi->widening = (signed char*)allocate_clean(ci, code_len+1); |
|
966 |
mi->injections = (Injection *)allocate_clean(ci, |
|
967 |
(int)((code_len+1)*sizeof(Injection))); |
|
968 |
mi->number = mnum; |
|
969 |
ci->current_mi = mi; |
|
970 |
return mi; |
|
971 |
} |
|
972 |
||
973 |
static void |
|
974 |
method_term(MethodImage *mi) |
|
975 |
{ |
|
976 |
CrwClassImage *ci; |
|
977 |
||
978 |
ci = mi->ci; |
|
979 |
CRW_ASSERT_MI(mi); |
|
980 |
if ( mi->map != NULL ) { |
|
981 |
deallocate(ci, (void*)mi->map); |
|
982 |
mi->map = NULL; |
|
983 |
} |
|
984 |
if ( mi->widening != NULL ) { |
|
985 |
deallocate(ci, (void*)mi->widening); |
|
986 |
mi->widening = NULL; |
|
987 |
} |
|
988 |
if ( mi->injections != NULL ) { |
|
989 |
ByteOffset i; |
|
990 |
for(i=0; i<= mi->code_len; i++) { |
|
991 |
if ( mi->injections[i].code != NULL ) { |
|
992 |
deallocate(ci, (void*)mi->injections[i].code); |
|
993 |
mi->injections[i].code = NULL; |
|
994 |
} |
|
995 |
} |
|
996 |
deallocate(ci, (void*)mi->injections); |
|
997 |
mi->injections = NULL; |
|
998 |
} |
|
999 |
ci->current_mi = NULL; |
|
1000 |
deallocate(ci, (void*)mi); |
|
1001 |
} |
|
1002 |
||
1003 |
static ByteOffset |
|
1004 |
input_code_offset(MethodImage *mi) |
|
1005 |
{ |
|
1006 |
CRW_ASSERT_MI(mi); |
|
1007 |
return (ByteOffset)(mi->ci->input_position - mi->start_of_input_bytecodes); |
|
1008 |
} |
|
1009 |
||
1010 |
static void |
|
1011 |
rewind_to_beginning_of_input_bytecodes(MethodImage *mi) |
|
1012 |
{ |
|
1013 |
CRW_ASSERT_MI(mi); |
|
1014 |
mi->ci->input_position = mi->start_of_input_bytecodes; |
|
1015 |
} |
|
1016 |
||
1017 |
/* Starting at original byte position 'at', add 'offset' to it's new |
|
1018 |
* location. This may be a negative value. |
|
1019 |
* NOTE: That this map is not the new bytecode location of the opcode |
|
1020 |
* but the new bytecode location that should be used when |
|
1021 |
* a goto or jump instruction was targeting the old bytecode |
|
1022 |
* location. |
|
1023 |
*/ |
|
1024 |
static void |
|
1025 |
adjust_map(MethodImage *mi, ByteOffset at, ByteOffset offset) |
|
1026 |
{ |
|
1027 |
ByteOffset i; |
|
1028 |
||
1029 |
CRW_ASSERT_MI(mi); |
|
1030 |
for (i = at; i <= mi->code_len; ++i) { |
|
1031 |
mi->map[i] += offset; |
|
1032 |
} |
|
1033 |
} |
|
1034 |
||
1035 |
static void |
|
1036 |
widen(MethodImage *mi, ByteOffset at, ByteOffset len) |
|
1037 |
{ |
|
1038 |
int delta; |
|
1039 |
||
1040 |
CRW_ASSERT(mi->ci, at <= mi->code_len); |
|
1041 |
delta = len - mi->widening[at]; |
|
1042 |
/* Adjust everything from the current input location by delta */ |
|
1043 |
adjust_map(mi, input_code_offset(mi), delta); |
|
1044 |
/* Mark at beginning of instruction */ |
|
1045 |
mi->widening[at] = (signed char)len; |
|
1046 |
} |
|
1047 |
||
1048 |
static void |
|
1049 |
verify_opc_wide(CrwClassImage *ci, ClassOpcode wopcode) |
|
1050 |
{ |
|
1051 |
switch (wopcode) { |
|
1052 |
case JVM_OPC_aload: case JVM_OPC_astore: |
|
1053 |
case JVM_OPC_fload: case JVM_OPC_fstore: |
|
1054 |
case JVM_OPC_iload: case JVM_OPC_istore: |
|
1055 |
case JVM_OPC_lload: case JVM_OPC_lstore: |
|
1056 |
case JVM_OPC_dload: case JVM_OPC_dstore: |
|
1057 |
case JVM_OPC_ret: case JVM_OPC_iinc: |
|
1058 |
break; |
|
1059 |
default: |
|
1060 |
CRW_FATAL(ci, "Invalid opcode supplied to wide opcode"); |
|
1061 |
break; |
|
1062 |
} |
|
1063 |
} |
|
1064 |
||
1065 |
static unsigned |
|
1066 |
opcode_length(CrwClassImage *ci, ClassOpcode opcode) |
|
1067 |
{ |
|
1068 |
/* Define array that holds length of an opcode */ |
|
1069 |
static unsigned char _opcode_length[JVM_OPC_MAX+1] = |
|
1070 |
JVM_OPCODE_LENGTH_INITIALIZER; |
|
1071 |
||
1072 |
if ( opcode > JVM_OPC_MAX ) { |
|
1073 |
CRW_FATAL(ci, "Invalid opcode supplied to opcode_length()"); |
|
1074 |
} |
|
1075 |
return _opcode_length[opcode]; |
|
1076 |
} |
|
1077 |
||
1078 |
/* Walk one instruction and inject instrumentation */ |
|
1079 |
static void |
|
1080 |
inject_for_opcode(MethodImage *mi) |
|
1081 |
{ |
|
1082 |
CrwClassImage * ci; |
|
1083 |
ClassOpcode opcode; |
|
1084 |
int pos; |
|
1085 |
||
1086 |
CRW_ASSERT_MI(mi); |
|
1087 |
ci = mi->ci; |
|
1088 |
pos = input_code_offset(mi); |
|
1089 |
opcode = readU1(ci); |
|
1090 |
||
1091 |
if (opcode == JVM_OPC_wide) { |
|
1092 |
ClassOpcode wopcode; |
|
1093 |
||
1094 |
wopcode = readU1(ci); |
|
1095 |
/* lvIndex not used */ |
|
1096 |
(void)readU2(ci); |
|
1097 |
verify_opc_wide(ci, wopcode); |
|
1098 |
if ( wopcode==JVM_OPC_iinc ) { |
|
1099 |
(void)readU1(ci); |
|
1100 |
(void)readU1(ci); |
|
1101 |
} |
|
1102 |
} else { |
|
1103 |
||
1104 |
ByteCode bytecodes[LARGEST_INJECTION+1]; |
|
1105 |
int header; |
|
1106 |
int instr_len; |
|
1107 |
int low; |
|
1108 |
int high; |
|
1109 |
int npairs; |
|
1110 |
ByteOffset len; |
|
1111 |
||
1112 |
/* Get bytecodes to inject before this opcode */ |
|
1113 |
len = before_injection_code(mi, opcode, bytecodes, (int)sizeof(bytecodes)); |
|
1114 |
if ( len > 0 ) { |
|
1115 |
inject_bytecodes(mi, pos, bytecodes, len); |
|
1116 |
/* Adjust map after processing this opcode */ |
|
1117 |
} |
|
1118 |
||
1119 |
/* Process this opcode */ |
|
1120 |
switch (opcode) { |
|
1121 |
case JVM_OPC_tableswitch: |
|
1122 |
header = NEXT_4BYTE_BOUNDARY(pos); |
|
1123 |
skip(ci, header - (pos+1)); |
|
1124 |
(void)readU4(ci); |
|
1125 |
low = readU4(ci); |
|
1126 |
high = readU4(ci); |
|
1127 |
skip(ci, (high+1-low) * 4); |
|
1128 |
break; |
|
1129 |
case JVM_OPC_lookupswitch: |
|
1130 |
header = NEXT_4BYTE_BOUNDARY(pos); |
|
1131 |
skip(ci, header - (pos+1)); |
|
1132 |
(void)readU4(ci); |
|
1133 |
npairs = readU4(ci); |
|
1134 |
skip(ci, npairs * 8); |
|
1135 |
break; |
|
1136 |
default: |
|
1137 |
instr_len = opcode_length(ci, opcode); |
|
1138 |
skip(ci, instr_len-1); |
|
1139 |
break; |
|
1140 |
} |
|
1141 |
||
1142 |
/* Get position after this opcode is processed */ |
|
1143 |
pos = input_code_offset(mi); |
|
1144 |
||
1145 |
/* Adjust for any before_injection_code() */ |
|
1146 |
if ( len > 0 ) { |
|
1147 |
/* Adjust everything past this opcode. |
|
1148 |
* Why past it? Because we want any jumps to this bytecode loc |
|
1149 |
* to go to the injected code, not where the opcode |
|
1150 |
* was moved too. |
|
1151 |
* Consider a 'return' opcode that is jumped too. |
|
1152 |
* NOTE: This may not be correct in all cases, but will |
|
1153 |
* when we are only dealing with non-variable opcodes |
|
1154 |
* like the return opcodes. Be careful if the |
|
1155 |
* before_injection_code() changes to include other |
|
1156 |
* opcodes that have variable length. |
|
1157 |
*/ |
|
1158 |
adjust_map(mi, pos, len); |
|
1159 |
} |
|
1160 |
||
1161 |
/* Get bytecodes to inject after this opcode */ |
|
1162 |
len = after_injection_code(mi, opcode, bytecodes, (int)sizeof(bytecodes)); |
|
1163 |
if ( len > 0 ) { |
|
1164 |
inject_bytecodes(mi, pos, bytecodes, len); |
|
1165 |
||
1166 |
/* Adjust for any after_injection_code() */ |
|
1167 |
adjust_map(mi, pos, len); |
|
1168 |
} |
|
1169 |
||
1170 |
} |
|
1171 |
} |
|
1172 |
||
1173 |
/* Map original bytecode location to it's new location. (See adjust_map()). */ |
|
1174 |
static ByteOffset |
|
1175 |
method_code_map(MethodImage *mi, ByteOffset pos) |
|
1176 |
{ |
|
1177 |
CRW_ASSERT_MI(mi); |
|
1178 |
CRW_ASSERT(mi->ci, pos <= mi->code_len); |
|
1179 |
return mi->map[pos]; |
|
1180 |
} |
|
1181 |
||
1182 |
static int |
|
1183 |
adjust_instruction(MethodImage *mi) |
|
1184 |
{ |
|
1185 |
CrwClassImage * ci; |
|
1186 |
ClassOpcode opcode; |
|
1187 |
int pos; |
|
1188 |
int new_pos; |
|
1189 |
||
1190 |
CRW_ASSERT_MI(mi); |
|
1191 |
ci = mi->ci; |
|
1192 |
pos = input_code_offset(mi); |
|
1193 |
new_pos = method_code_map(mi,pos); |
|
1194 |
||
1195 |
opcode = readU1(ci); |
|
1196 |
||
1197 |
if (opcode == JVM_OPC_wide) { |
|
1198 |
ClassOpcode wopcode; |
|
1199 |
||
1200 |
wopcode = readU1(ci); |
|
1201 |
/* lvIndex not used */ |
|
1202 |
(void)readU2(ci); |
|
1203 |
verify_opc_wide(ci, wopcode); |
|
1204 |
if ( wopcode==JVM_OPC_iinc ) { |
|
1205 |
(void)readU1(ci); |
|
1206 |
(void)readU1(ci); |
|
1207 |
} |
|
1208 |
} else { |
|
1209 |
||
1210 |
int widened; |
|
1211 |
int header; |
|
1212 |
int newHeader; |
|
1213 |
int low; |
|
1214 |
int high; |
|
1215 |
int new_pad; |
|
1216 |
int old_pad; |
|
1217 |
int delta; |
|
1218 |
int new_delta; |
|
1219 |
int delta_pad; |
|
1220 |
int npairs; |
|
1221 |
int instr_len; |
|
1222 |
||
1223 |
switch (opcode) { |
|
1224 |
||
1225 |
case JVM_OPC_tableswitch: |
|
1226 |
widened = mi->widening[pos]; |
|
1227 |
header = NEXT_4BYTE_BOUNDARY(pos); |
|
1228 |
newHeader = NEXT_4BYTE_BOUNDARY(new_pos); |
|
1229 |
||
1230 |
skip(ci, header - (pos+1)); |
|
1231 |
||
1232 |
delta = readU4(ci); |
|
1233 |
low = readU4(ci); |
|
1234 |
high = readU4(ci); |
|
1235 |
skip(ci, (high+1-low) * 4); |
|
1236 |
new_pad = newHeader - new_pos; |
|
1237 |
old_pad = header - pos; |
|
1238 |
delta_pad = new_pad - old_pad; |
|
1239 |
if (widened != delta_pad) { |
|
1240 |
widen(mi, pos, delta_pad); |
|
1241 |
return 0; |
|
1242 |
} |
|
1243 |
break; |
|
1244 |
||
1245 |
case JVM_OPC_lookupswitch: |
|
1246 |
widened = mi->widening[pos]; |
|
1247 |
header = NEXT_4BYTE_BOUNDARY(pos); |
|
1248 |
newHeader = NEXT_4BYTE_BOUNDARY(new_pos); |
|
1249 |
||
1250 |
skip(ci, header - (pos+1)); |
|
1251 |
||
1252 |
delta = readU4(ci); |
|
1253 |
npairs = readU4(ci); |
|
1254 |
skip(ci, npairs * 8); |
|
1255 |
new_pad = newHeader - new_pos; |
|
1256 |
old_pad = header - pos; |
|
1257 |
delta_pad = new_pad - old_pad; |
|
1258 |
if (widened != delta_pad) { |
|
1259 |
widen(mi, pos, delta_pad); |
|
1260 |
return 0; |
|
1261 |
} |
|
1262 |
break; |
|
1263 |
||
1264 |
case JVM_OPC_jsr: case JVM_OPC_goto: |
|
1265 |
case JVM_OPC_ifeq: case JVM_OPC_ifge: case JVM_OPC_ifgt: |
|
1266 |
case JVM_OPC_ifle: case JVM_OPC_iflt: case JVM_OPC_ifne: |
|
1267 |
case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmpge: |
|
1268 |
case JVM_OPC_if_icmpgt: case JVM_OPC_if_icmple: case JVM_OPC_if_icmplt: |
|
1269 |
case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne: |
|
1270 |
case JVM_OPC_ifnull: case JVM_OPC_ifnonnull: |
|
1271 |
widened = mi->widening[pos]; |
|
1272 |
delta = readS2(ci); |
|
1273 |
if (widened == 0) { |
|
1274 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1275 |
if ((new_delta < -32768) || (new_delta > 32767)) { |
|
1276 |
switch (opcode) { |
|
1277 |
case JVM_OPC_jsr: case JVM_OPC_goto: |
|
1278 |
widen(mi, pos, 2); |
|
1279 |
break; |
|
1280 |
default: |
|
1281 |
widen(mi, pos, 5); |
|
1282 |
break; |
|
1283 |
} |
|
1284 |
return 0; |
|
1285 |
} |
|
1286 |
} |
|
1287 |
break; |
|
1288 |
||
1289 |
case JVM_OPC_jsr_w: |
|
1290 |
case JVM_OPC_goto_w: |
|
1291 |
(void)readU4(ci); |
|
1292 |
break; |
|
1293 |
||
1294 |
default: |
|
1295 |
instr_len = opcode_length(ci, opcode); |
|
1296 |
skip(ci, instr_len-1); |
|
1297 |
break; |
|
1298 |
} |
|
1299 |
} |
|
1300 |
return 1; |
|
1301 |
} |
|
1302 |
||
1303 |
static void |
|
1304 |
write_instruction(MethodImage *mi) |
|
1305 |
{ |
|
1306 |
CrwClassImage * ci; |
|
1307 |
ClassOpcode opcode; |
|
1308 |
ByteOffset new_code_len; |
|
1309 |
int pos; |
|
1310 |
int new_pos; |
|
1311 |
||
1312 |
CRW_ASSERT_MI(mi); |
|
1313 |
ci = mi->ci; |
|
1314 |
pos = input_code_offset(mi); |
|
1315 |
new_pos = method_code_map(mi,pos); |
|
1316 |
new_code_len = mi->injections[pos].len; |
|
1317 |
if (new_code_len > 0) { |
|
1318 |
write_bytes(ci, (void*)mi->injections[pos].code, new_code_len); |
|
1319 |
} |
|
1320 |
||
1321 |
opcode = readU1(ci); |
|
1322 |
if (opcode == JVM_OPC_wide) { |
|
1323 |
ClassOpcode wopcode; |
|
1324 |
||
1325 |
writeU1(ci, opcode); |
|
1326 |
||
1327 |
wopcode = copyU1(ci); |
|
1328 |
/* lvIndex not used */ |
|
1329 |
(void)copyU2(ci); |
|
1330 |
verify_opc_wide(ci, wopcode); |
|
1331 |
if ( wopcode==JVM_OPC_iinc ) { |
|
1332 |
(void)copyU1(ci); |
|
1333 |
(void)copyU1(ci); |
|
1334 |
} |
|
1335 |
} else { |
|
1336 |
||
1337 |
ClassOpcode new_opcode; |
|
1338 |
int header; |
|
1339 |
int newHeader; |
|
1340 |
int low; |
|
1341 |
int high; |
|
1342 |
int i; |
|
1343 |
int npairs; |
|
1344 |
int widened; |
|
1345 |
int instr_len; |
|
1346 |
int delta; |
|
1347 |
int new_delta; |
|
1348 |
||
1349 |
switch (opcode) { |
|
1350 |
||
1351 |
case JVM_OPC_tableswitch: |
|
1352 |
header = NEXT_4BYTE_BOUNDARY(pos); |
|
1353 |
newHeader = NEXT_4BYTE_BOUNDARY(new_pos); |
|
1354 |
||
1355 |
skip(ci, header - (pos+1)); |
|
1356 |
||
1357 |
delta = readU4(ci); |
|
1358 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1359 |
low = readU4(ci); |
|
1360 |
high = readU4(ci); |
|
1361 |
||
1362 |
writeU1(ci, opcode); |
|
1363 |
for (i = new_pos+1; i < newHeader; ++i) { |
|
1364 |
writeU1(ci, 0); |
|
1365 |
} |
|
1366 |
writeU4(ci, new_delta); |
|
1367 |
writeU4(ci, low); |
|
1368 |
writeU4(ci, high); |
|
1369 |
||
1370 |
for (i = low; i <= high; ++i) { |
|
1371 |
delta = readU4(ci); |
|
1372 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1373 |
writeU4(ci, new_delta); |
|
1374 |
} |
|
1375 |
break; |
|
1376 |
||
1377 |
case JVM_OPC_lookupswitch: |
|
1378 |
header = NEXT_4BYTE_BOUNDARY(pos); |
|
1379 |
newHeader = NEXT_4BYTE_BOUNDARY(new_pos); |
|
1380 |
||
1381 |
skip(ci, header - (pos+1)); |
|
1382 |
||
1383 |
delta = readU4(ci); |
|
1384 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1385 |
npairs = readU4(ci); |
|
1386 |
writeU1(ci, opcode); |
|
1387 |
for (i = new_pos+1; i < newHeader; ++i) { |
|
1388 |
writeU1(ci, 0); |
|
1389 |
} |
|
1390 |
writeU4(ci, new_delta); |
|
1391 |
writeU4(ci, npairs); |
|
1392 |
for (i = 0; i< npairs; ++i) { |
|
1393 |
unsigned match = readU4(ci); |
|
1394 |
delta = readU4(ci); |
|
1395 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1396 |
writeU4(ci, match); |
|
1397 |
writeU4(ci, new_delta); |
|
1398 |
} |
|
1399 |
break; |
|
1400 |
||
1401 |
case JVM_OPC_jsr: case JVM_OPC_goto: |
|
1402 |
case JVM_OPC_ifeq: case JVM_OPC_ifge: case JVM_OPC_ifgt: |
|
1403 |
case JVM_OPC_ifle: case JVM_OPC_iflt: case JVM_OPC_ifne: |
|
1404 |
case JVM_OPC_if_icmpeq: case JVM_OPC_if_icmpne: case JVM_OPC_if_icmpge: |
|
1405 |
case JVM_OPC_if_icmpgt: case JVM_OPC_if_icmple: case JVM_OPC_if_icmplt: |
|
1406 |
case JVM_OPC_if_acmpeq: case JVM_OPC_if_acmpne: |
|
1407 |
case JVM_OPC_ifnull: case JVM_OPC_ifnonnull: |
|
1408 |
widened = mi->widening[pos]; |
|
1409 |
delta = readS2(ci); |
|
1410 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1411 |
new_opcode = opcode; |
|
1412 |
if (widened == 0) { |
|
1413 |
writeU1(ci, opcode); |
|
1414 |
writeU2(ci, new_delta); |
|
1415 |
} else if (widened == 2) { |
|
1416 |
switch (opcode) { |
|
1417 |
case JVM_OPC_jsr: |
|
1418 |
new_opcode = JVM_OPC_jsr_w; |
|
1419 |
break; |
|
1420 |
case JVM_OPC_goto: |
|
1421 |
new_opcode = JVM_OPC_goto_w; |
|
1422 |
break; |
|
1423 |
default: |
|
1424 |
CRW_FATAL(ci, "unexpected opcode"); |
|
1425 |
break; |
|
1426 |
} |
|
1427 |
writeU1(ci, new_opcode); |
|
1428 |
writeU4(ci, new_delta); |
|
1429 |
} else if (widened == 5) { |
|
1430 |
switch (opcode) { |
|
1431 |
case JVM_OPC_ifeq: |
|
1432 |
new_opcode = JVM_OPC_ifne; |
|
1433 |
break; |
|
1434 |
case JVM_OPC_ifge: |
|
1435 |
new_opcode = JVM_OPC_iflt; |
|
1436 |
break; |
|
1437 |
case JVM_OPC_ifgt: |
|
1438 |
new_opcode = JVM_OPC_ifle; |
|
1439 |
break; |
|
1440 |
case JVM_OPC_ifle: |
|
1441 |
new_opcode = JVM_OPC_ifgt; |
|
1442 |
break; |
|
1443 |
case JVM_OPC_iflt: |
|
1444 |
new_opcode = JVM_OPC_ifge; |
|
1445 |
break; |
|
1446 |
case JVM_OPC_ifne: |
|
1447 |
new_opcode = JVM_OPC_ifeq; |
|
1448 |
break; |
|
1449 |
case JVM_OPC_if_icmpeq: |
|
1450 |
new_opcode = JVM_OPC_if_icmpne; |
|
1451 |
break; |
|
1452 |
case JVM_OPC_if_icmpne: |
|
1453 |
new_opcode = JVM_OPC_if_icmpeq; |
|
1454 |
break; |
|
1455 |
case JVM_OPC_if_icmpge: |
|
1456 |
new_opcode = JVM_OPC_if_icmplt; |
|
1457 |
break; |
|
1458 |
case JVM_OPC_if_icmpgt: |
|
1459 |
new_opcode = JVM_OPC_if_icmple; |
|
1460 |
break; |
|
1461 |
case JVM_OPC_if_icmple: |
|
1462 |
new_opcode = JVM_OPC_if_icmpgt; |
|
1463 |
break; |
|
1464 |
case JVM_OPC_if_icmplt: |
|
1465 |
new_opcode = JVM_OPC_if_icmpge; |
|
1466 |
break; |
|
1467 |
case JVM_OPC_if_acmpeq: |
|
1468 |
new_opcode = JVM_OPC_if_acmpne; |
|
1469 |
break; |
|
1470 |
case JVM_OPC_if_acmpne: |
|
1471 |
new_opcode = JVM_OPC_if_acmpeq; |
|
1472 |
break; |
|
1473 |
case JVM_OPC_ifnull: |
|
1474 |
new_opcode = JVM_OPC_ifnonnull; |
|
1475 |
break; |
|
1476 |
case JVM_OPC_ifnonnull: |
|
1477 |
new_opcode = JVM_OPC_ifnull; |
|
1478 |
break; |
|
1479 |
default: |
|
1480 |
CRW_FATAL(ci, "Unexpected opcode"); |
|
1481 |
break; |
|
1482 |
} |
|
1483 |
writeU1(ci, new_opcode); /* write inverse branch */ |
|
1484 |
writeU2(ci, 3 + 5); /* beyond if and goto_w */ |
|
1485 |
writeU1(ci, JVM_OPC_goto_w); /* add a goto_w */ |
|
1486 |
writeU4(ci, new_delta-3); /* write new and wide delta */ |
|
1487 |
} else { |
|
1488 |
CRW_FATAL(ci, "Unexpected widening"); |
|
1489 |
} |
|
1490 |
break; |
|
1491 |
||
1492 |
case JVM_OPC_jsr_w: |
|
1493 |
case JVM_OPC_goto_w: |
|
1494 |
delta = readU4(ci); |
|
1495 |
new_delta = method_code_map(mi,pos+delta) - new_pos; |
|
1496 |
writeU1(ci, opcode); |
|
1497 |
writeU4(ci, new_delta); |
|
1498 |
break; |
|
1499 |
||
1500 |
default: |
|
1501 |
instr_len = opcode_length(ci, opcode); |
|
1502 |
writeU1(ci, opcode); |
|
1503 |
copy(ci, instr_len-1); |
|
1504 |
break; |
|
1505 |
} |
|
1506 |
} |
|
1507 |
} |
|
1508 |
||
1509 |
static void |
|
1510 |
method_inject_and_write_code(MethodImage *mi) |
|
1511 |
{ |
|
1512 |
ByteCode bytecodes[LARGEST_INJECTION+1]; |
|
1513 |
ByteOffset len; |
|
1514 |
||
1515 |
CRW_ASSERT_MI(mi); |
|
1516 |
||
1517 |
/* Do injections */ |
|
1518 |
rewind_to_beginning_of_input_bytecodes(mi); |
|
1519 |
len = entry_injection_code(mi, bytecodes, (int)sizeof(bytecodes)); |
|
1520 |
if ( len > 0 ) { |
|
1521 |
int pos; |
|
1522 |
||
1523 |
pos = 0; |
|
1524 |
inject_bytecodes(mi, pos, bytecodes, len); |
|
1525 |
/* Adjust pos 0 to map to new pos 0, you never want to |
|
1526 |
* jump into this entry code injection. So the new pos 0 |
|
1527 |
* will be past this entry_injection_code(). |
|
1528 |
*/ |
|
1529 |
adjust_map(mi, pos, len); /* Inject before behavior */ |
|
1530 |
} |
|
1531 |
while (input_code_offset(mi) < mi->code_len) { |
|
1532 |
inject_for_opcode(mi); |
|
1533 |
} |
|
1534 |
||
1535 |
/* Adjust instructions */ |
|
1536 |
rewind_to_beginning_of_input_bytecodes(mi); |
|
1537 |
while (input_code_offset(mi) < mi->code_len) { |
|
1538 |
if (!adjust_instruction(mi)) { |
|
1539 |
rewind_to_beginning_of_input_bytecodes(mi); |
|
1540 |
} |
|
1541 |
} |
|
1542 |
||
1543 |
/* Write new instructions */ |
|
1544 |
rewind_to_beginning_of_input_bytecodes(mi); |
|
1545 |
while (input_code_offset(mi) < mi->code_len) { |
|
1546 |
write_instruction(mi); |
|
1547 |
} |
|
1548 |
} |
|
1549 |
||
1550 |
static void |
|
1551 |
copy_attribute(CrwClassImage *ci) |
|
1552 |
{ |
|
1553 |
int len; |
|
1554 |
||
1555 |
(void)copyU2(ci); |
|
1556 |
len = copyU4(ci); |
|
1557 |
copy(ci, len); |
|
1558 |
} |
|
1559 |
||
1560 |
static void |
|
1561 |
copy_attributes(CrwClassImage *ci) |
|
1562 |
{ |
|
1563 |
unsigned i; |
|
1564 |
unsigned count; |
|
1565 |
||
1566 |
count = copyU2(ci); |
|
1567 |
for (i = 0; i < count; ++i) { |
|
1568 |
copy_attribute(ci); |
|
1569 |
} |
|
1570 |
} |
|
1571 |
||
1572 |
static void |
|
1573 |
copy_all_fields(CrwClassImage *ci) |
|
1574 |
{ |
|
1575 |
unsigned i; |
|
1576 |
unsigned count; |
|
1577 |
||
1578 |
count = copyU2(ci); |
|
1579 |
for (i = 0; i < count; ++i) { |
|
1580 |
/* access, name, descriptor */ |
|
1581 |
copy(ci, 6); |
|
1582 |
copy_attributes(ci); |
|
1583 |
} |
|
1584 |
} |
|
1585 |
||
1586 |
static void |
|
1587 |
write_line_table(MethodImage *mi) |
|
1588 |
{ |
|
1589 |
unsigned i; |
|
1590 |
unsigned count; |
|
1591 |
CrwClassImage * ci; |
|
1592 |
||
1593 |
CRW_ASSERT_MI(mi); |
|
1594 |
ci = mi->ci; |
|
1595 |
(void)copyU4(ci); |
|
1596 |
count = copyU2(ci); |
|
1597 |
for(i=0; i<count; i++) { |
|
1598 |
ByteOffset start_pc; |
|
1599 |
ByteOffset new_start_pc; |
|
1600 |
||
1601 |
start_pc = readU2(ci); |
|
1602 |
||
1603 |
if ( start_pc == 0 ) { |
|
1604 |
new_start_pc = 0; /* Don't skip entry injection code. */ |
|
1605 |
} else { |
|
1606 |
new_start_pc = method_code_map(mi, start_pc); |
|
1607 |
} |
|
1608 |
||
1609 |
writeU2(ci, new_start_pc); |
|
1610 |
(void)copyU2(ci); |
|
1611 |
} |
|
1612 |
} |
|
1613 |
||
1614 |
/* Used for LocalVariableTable and LocalVariableTypeTable attributes */ |
|
1615 |
static void |
|
1616 |
write_var_table(MethodImage *mi) |
|
1617 |
{ |
|
1618 |
unsigned i; |
|
1619 |
unsigned count; |
|
1620 |
CrwClassImage * ci; |
|
1621 |
||
1622 |
CRW_ASSERT_MI(mi); |
|
1623 |
ci = mi->ci; |
|
1624 |
(void)copyU4(ci); |
|
1625 |
count = copyU2(ci); |
|
1626 |
for(i=0; i<count; i++) { |
|
1627 |
ByteOffset start_pc; |
|
1628 |
ByteOffset new_start_pc; |
|
1629 |
ByteOffset length; |
|
1630 |
ByteOffset new_length; |
|
1631 |
ByteOffset end_pc; |
|
1632 |
ByteOffset new_end_pc; |
|
1633 |
||
1634 |
start_pc = readU2(ci); |
|
1635 |
length = readU2(ci); |
|
1636 |
||
1637 |
if ( start_pc == 0 ) { |
|
1638 |
new_start_pc = 0; /* Don't skip entry injection code. */ |
|
1639 |
} else { |
|
1640 |
new_start_pc = method_code_map(mi, start_pc); |
|
1641 |
} |
|
1642 |
end_pc = start_pc + length; |
|
1643 |
new_end_pc = method_code_map(mi, end_pc); |
|
1644 |
new_length = new_end_pc - new_start_pc; |
|
1645 |
||
1646 |
writeU2(ci, new_start_pc); |
|
1647 |
writeU2(ci, new_length); |
|
1648 |
(void)copyU2(ci); |
|
1649 |
(void)copyU2(ci); |
|
1650 |
(void)copyU2(ci); |
|
1651 |
} |
|
1652 |
} |
|
1653 |
||
1654 |
/* The uoffset field is u2 or u4 depending on the code_len. |
|
1655 |
* Note that the code_len is likely changing, so be careful here. |
|
1656 |
*/ |
|
1657 |
static unsigned |
|
1658 |
readUoffset(MethodImage *mi) |
|
1659 |
{ |
|
1660 |
if ( mi->code_len > 65535 ) { |
|
1661 |
return readU4(mi->ci); |
|
1662 |
} |
|
1663 |
return readU2(mi->ci); |
|
1664 |
} |
|
1665 |
||
1666 |
static void |
|
1667 |
writeUoffset(MethodImage *mi, unsigned val) |
|
1668 |
{ |
|
1669 |
if ( mi->new_code_len > 65535 ) { |
|
1670 |
writeU4(mi->ci, val); |
|
1671 |
} |
|
1672 |
writeU2(mi->ci, val); |
|
1673 |
} |
|
1674 |
||
1675 |
static unsigned |
|
1676 |
copyUoffset(MethodImage *mi) |
|
1677 |
{ |
|
1678 |
unsigned uoffset; |
|
1679 |
||
1680 |
uoffset = readUoffset(mi); |
|
1681 |
writeUoffset(mi, uoffset); |
|
1682 |
return uoffset; |
|
1683 |
} |
|
1684 |
||
1685 |
/* Copy over verification_type_info structure */ |
|
1686 |
static void |
|
1687 |
copy_verification_types(MethodImage *mi, int ntypes) |
|
1688 |
{ |
|
1689 |
/* If there were ntypes, we just copy that over, no changes */ |
|
1690 |
if ( ntypes > 0 ) { |
|
1691 |
int j; |
|
1692 |
||
1693 |
for ( j = 0 ; j < ntypes ; j++ ) { |
|
1694 |
unsigned tag; |
|
1695 |
||
1696 |
tag = copyU1(mi->ci); |
|
1697 |
switch ( tag ) { |
|
1698 |
case JVM_ITEM_Object: |
|
1699 |
(void)copyU2(mi->ci); /* Constant pool entry */ |
|
1700 |
break; |
|
1701 |
case JVM_ITEM_Uninitialized: |
|
1702 |
/* Code offset for 'new' opcode is for this object */ |
|
1703 |
writeUoffset(mi, method_code_map(mi, readUoffset(mi))); |
|
1704 |
break; |
|
1705 |
} |
|
1706 |
} |
|
1707 |
} |
|
1708 |
} |
|
1709 |
||
1710 |
/* Process the StackMapTable attribute. We didn't add any basic blocks |
|
1711 |
* so the frame count remains the same but we may need to process the |
|
1712 |
* frame types due to offset changes putting things out of range. |
|
1713 |
*/ |
|
1714 |
static void |
|
1715 |
write_stackmap_table(MethodImage *mi) |
|
1716 |
{ |
|
1717 |
CrwClassImage *ci; |
|
1718 |
CrwPosition save_position; |
|
1719 |
ByteOffset last_pc; |
|
1720 |
ByteOffset last_new_pc; |
|
1721 |
unsigned i; |
|
1722 |
unsigned attr_len; |
|
1723 |
unsigned new_attr_len; |
|
1724 |
unsigned count; |
|
1725 |
unsigned delta_adj; |
|
1726 |
||
1727 |
CRW_ASSERT_MI(mi); |
|
1728 |
ci = mi->ci; |
|
1729 |
||
1730 |
/* Save the position of the attribute length so we can fix it later */ |
|
1731 |
save_position = ci->output_position; |
|
1732 |
attr_len = copyU4(ci); |
|
1733 |
count = copyUoffset(mi); /* uoffset: number_of_entries */ |
|
1734 |
if ( count == 0 ) { |
|
1735 |
CRW_ASSERT(ci, attr_len==2); |
|
1736 |
return; |
|
1737 |
} |
|
1738 |
||
1739 |
/* Process entire stackmap */ |
|
1740 |
last_pc = 0; |
|
1741 |
last_new_pc = 0; |
|
1742 |
delta_adj = 0; |
|
1743 |
for ( i = 0 ; i < count ; i++ ) { |
|
1744 |
ByteOffset new_pc=0; /* new pc in instrumented code */ |
|
1745 |
unsigned ft; /* frame_type */ |
|
1746 |
int delta=0; /* pc delta */ |
|
1747 |
int new_delta=0; /* new pc delta */ |
|
1748 |
||
1749 |
ft = readU1(ci); |
|
1750 |
if ( ft <= 63 ) { |
|
1751 |
/* Frame Type: same_frame ([0,63]) */ |
|
1752 |
unsigned new_ft; /* new frame_type */ |
|
1753 |
||
1754 |
delta = (delta_adj + ft); |
|
1755 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1756 |
new_delta = new_pc - last_new_pc; |
|
1757 |
new_ft = (new_delta - delta_adj); |
|
1758 |
if ( new_ft > 63 ) { |
|
1759 |
/* Change to same_frame_extended (251) */ |
|
1760 |
new_ft = 251; |
|
1761 |
writeU1(ci, new_ft); |
|
1762 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1763 |
} else { |
|
1764 |
writeU1(ci, new_ft); |
|
1765 |
} |
|
1766 |
} else if ( ft >= 64 && ft <= 127 ) { |
|
1767 |
/* Frame Type: same_locals_1_stack_item_frame ([64,127]) */ |
|
1768 |
unsigned new_ft; /* new frame_type */ |
|
1769 |
||
1770 |
delta = (delta_adj + ft - 64); |
|
1771 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1772 |
new_delta = new_pc - last_new_pc; |
|
1773 |
if ( (new_delta - delta_adj) > 63 ) { |
|
1774 |
/* Change to same_locals_1_stack_item_frame_extended (247) */ |
|
1775 |
new_ft = 247; |
|
1776 |
writeU1(ci, new_ft); |
|
1777 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1778 |
} else { |
|
1779 |
new_ft = (new_delta - delta_adj) + 64; |
|
1780 |
writeU1(ci, new_ft); |
|
1781 |
} |
|
1782 |
copy_verification_types(mi, 1); |
|
1783 |
} else if ( ft >= 128 && ft <= 246 ) { |
|
1784 |
/* Frame Type: reserved_for_future_use ([128,246]) */ |
|
1785 |
CRW_FATAL(ci, "Unknown frame type in StackMapTable attribute"); |
|
1786 |
} else if ( ft == 247 ) { |
|
1787 |
/* Frame Type: same_locals_1_stack_item_frame_extended (247) */ |
|
1788 |
delta = (delta_adj + readUoffset(mi)); |
|
1789 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1790 |
new_delta = new_pc - last_new_pc; |
|
1791 |
writeU1(ci, ft); |
|
1792 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1793 |
copy_verification_types(mi, 1); |
|
1794 |
} else if ( ft >= 248 && ft <= 250 ) { |
|
1795 |
/* Frame Type: chop_frame ([248,250]) */ |
|
1796 |
delta = (delta_adj + readUoffset(mi)); |
|
1797 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1798 |
new_delta = new_pc - last_new_pc; |
|
1799 |
writeU1(ci, ft); |
|
1800 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1801 |
} else if ( ft == 251 ) { |
|
1802 |
/* Frame Type: same_frame_extended (251) */ |
|
1803 |
delta = (delta_adj + readUoffset(mi)); |
|
1804 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1805 |
new_delta = new_pc - last_new_pc; |
|
1806 |
writeU1(ci, ft); |
|
1807 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1808 |
} else if ( ft >= 252 && ft <= 254 ) { |
|
1809 |
/* Frame Type: append_frame ([252,254]) */ |
|
1810 |
delta = (delta_adj + readUoffset(mi)); |
|
1811 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1812 |
new_delta = new_pc - last_new_pc; |
|
1813 |
writeU1(ci, ft); |
|
1814 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1815 |
copy_verification_types(mi, (ft - 251)); |
|
1816 |
} else if ( ft == 255 ) { |
|
1817 |
unsigned ntypes; |
|
1818 |
||
1819 |
/* Frame Type: full_frame (255) */ |
|
1820 |
delta = (delta_adj + readUoffset(mi)); |
|
1821 |
new_pc = method_code_map(mi, last_pc + delta); |
|
1822 |
new_delta = new_pc - last_new_pc; |
|
1823 |
writeU1(ci, ft); |
|
1824 |
writeUoffset(mi, (new_delta - delta_adj)); |
|
1825 |
ntypes = copyU2(ci); /* ulocalvar */ |
|
1826 |
copy_verification_types(mi, ntypes); |
|
1827 |
ntypes = copyU2(ci); /* ustack */ |
|
1828 |
copy_verification_types(mi, ntypes); |
|
1829 |
} |
|
1830 |
||
1831 |
/* Update last_pc and last_new_pc (save on calls to method_code_map) */ |
|
1832 |
CRW_ASSERT(ci, delta >= 0); |
|
1833 |
CRW_ASSERT(ci, new_delta >= 0); |
|
1834 |
last_pc += delta; |
|
1835 |
last_new_pc = new_pc; |
|
1836 |
CRW_ASSERT(ci, last_pc <= mi->code_len); |
|
1837 |
CRW_ASSERT(ci, last_new_pc <= mi->new_code_len); |
|
1838 |
||
1839 |
/* Delta adjustment, all deltas are -1 now in attribute */ |
|
1840 |
delta_adj = 1; |
|
1841 |
} |
|
1842 |
||
1843 |
/* Update the attribute length */ |
|
1844 |
new_attr_len = ci->output_position - (save_position + 4); |
|
1845 |
CRW_ASSERT(ci, new_attr_len >= attr_len); |
|
1846 |
random_writeU4(ci, save_position, new_attr_len); |
|
1847 |
} |
|
1848 |
||
1849 |
/* Process the CLDC StackMap attribute. We didn't add any basic blocks |
|
1850 |
* so the frame count remains the same but we may need to process the |
|
1851 |
* frame types due to offset changes putting things out of range. |
|
1852 |
*/ |
|
1853 |
static void |
|
1854 |
write_cldc_stackmap_table(MethodImage *mi) |
|
1855 |
{ |
|
1856 |
CrwClassImage *ci; |
|
1857 |
CrwPosition save_position; |
|
1858 |
unsigned i; |
|
1859 |
unsigned attr_len; |
|
1860 |
unsigned new_attr_len; |
|
1861 |
unsigned count; |
|
1862 |
||
1863 |
CRW_ASSERT_MI(mi); |
|
1864 |
ci = mi->ci; |
|
1865 |
||
1866 |
/* Save the position of the attribute length so we can fix it later */ |
|
1867 |
save_position = ci->output_position; |
|
1868 |
attr_len = copyU4(ci); |
|
1869 |
count = copyUoffset(mi); /* uoffset: number_of_entries */ |
|
1870 |
if ( count == 0 ) { |
|
1871 |
CRW_ASSERT(ci, attr_len==2); |
|
1872 |
return; |
|
1873 |
} |
|
1874 |
||
1875 |
/* Process entire stackmap */ |
|
1876 |
for ( i = 0 ; i < count ; i++ ) { |
|
1877 |
unsigned ntypes; |
|
1878 |
||
1879 |
writeUoffset(mi, method_code_map(mi, readUoffset(mi))); |
|
1880 |
ntypes = copyU2(ci); /* ulocalvar */ |
|
1881 |
copy_verification_types(mi, ntypes); |
|
1882 |
ntypes = copyU2(ci); /* ustack */ |
|
1883 |
copy_verification_types(mi, ntypes); |
|
1884 |
} |
|
1885 |
||
1886 |
/* Update the attribute length */ |
|
1887 |
new_attr_len = ci->output_position - (save_position + 4); |
|
1888 |
CRW_ASSERT(ci, new_attr_len >= attr_len); |
|
1889 |
random_writeU4(ci, save_position, new_attr_len); |
|
1890 |
} |
|
1891 |
||
1892 |
static void |
|
1893 |
method_write_exception_table(MethodImage *mi) |
|
1894 |
{ |
|
1895 |
unsigned i; |
|
1896 |
unsigned count; |
|
1897 |
CrwClassImage * ci; |
|
1898 |
||
1899 |
CRW_ASSERT_MI(mi); |
|
1900 |
ci = mi->ci; |
|
1901 |
count = copyU2(ci); |
|
1902 |
for(i=0; i<count; i++) { |
|
1903 |
ByteOffset start_pc; |
|
1904 |
ByteOffset new_start_pc; |
|
1905 |
ByteOffset end_pc; |
|
1906 |
ByteOffset new_end_pc; |
|
1907 |
ByteOffset handler_pc; |
|
1908 |
ByteOffset new_handler_pc; |
|
1909 |
||
1910 |
start_pc = readU2(ci); |
|
1911 |
end_pc = readU2(ci); |
|
1912 |
handler_pc = readU2(ci); |
|
1913 |
||
1914 |
new_start_pc = method_code_map(mi, start_pc); |
|
1915 |
new_end_pc = method_code_map(mi, end_pc); |
|
1916 |
new_handler_pc = method_code_map(mi, handler_pc); |
|
1917 |
||
1918 |
writeU2(ci, new_start_pc); |
|
1919 |
writeU2(ci, new_end_pc); |
|
1920 |
writeU2(ci, new_handler_pc); |
|
1921 |
(void)copyU2(ci); |
|
1922 |
} |
|
1923 |
} |
|
1924 |
||
1925 |
static int |
|
1926 |
attribute_match(CrwClassImage *ci, CrwCpoolIndex name_index, const char *name) |
|
1927 |
{ |
|
1928 |
CrwConstantPoolEntry cs; |
|
1929 |
int len; |
|
1930 |
||
1931 |
CRW_ASSERT_CI(ci); |
|
1932 |
CRW_ASSERT(ci, name!=NULL); |
|
1933 |
len = (int)strlen(name); |
|
1934 |
cs = cpool_entry(ci, name_index); |
|
1935 |
if ( cs.len==len && strncmp(cs.ptr, name, len)==0) { |
|
1936 |
return 1; |
|
1937 |
} |
|
1938 |
return 0; |
|
1939 |
} |
|
1940 |
||
1941 |
static void |
|
1942 |
method_write_code_attribute(MethodImage *mi) |
|
1943 |
{ |
|
1944 |
CrwClassImage * ci; |
|
1945 |
CrwCpoolIndex name_index; |
|
1946 |
||
1947 |
CRW_ASSERT_MI(mi); |
|
1948 |
ci = mi->ci; |
|
1949 |
name_index = copyU2(ci); |
|
1950 |
if ( attribute_match(ci, name_index, "LineNumberTable") ) { |
|
1951 |
write_line_table(mi); |
|
1952 |
} else if ( attribute_match(ci, name_index, "LocalVariableTable") ) { |
|
1953 |
write_var_table(mi); |
|
1954 |
} else if ( attribute_match(ci, name_index, "LocalVariableTypeTable") ) { |
|
1955 |
write_var_table(mi); /* Exact same format as the LocalVariableTable */ |
|
1956 |
} else if ( attribute_match(ci, name_index, "StackMapTable") ) { |
|
1957 |
write_stackmap_table(mi); |
|
1958 |
} else if ( attribute_match(ci, name_index, "StackMap") ) { |
|
1959 |
write_cldc_stackmap_table(mi); |
|
1960 |
} else { |
|
1961 |
unsigned len; |
|
1962 |
len = copyU4(ci); |
|
1963 |
copy(ci, len); |
|
1964 |
} |
|
1965 |
} |
|
1966 |
||
1967 |
static int |
|
1968 |
is_init_method(const char *name) |
|
1969 |
{ |
|
1970 |
if ( name!=NULL && strcmp(name,"<init>")==0 ) { |
|
1971 |
return JNI_TRUE; |
|
1972 |
} |
|
1973 |
return JNI_FALSE; |
|
1974 |
} |
|
1975 |
||
1976 |
static int |
|
1977 |
is_clinit_method(const char *name) |
|
1978 |
{ |
|
1979 |
if ( name!=NULL && strcmp(name,"<clinit>")==0 ) { |
|
1980 |
return JNI_TRUE; |
|
1981 |
} |
|
1982 |
return JNI_FALSE; |
|
1983 |
} |
|
1984 |
||
1985 |
static int |
|
1986 |
is_finalize_method(const char *name) |
|
1987 |
{ |
|
1988 |
if ( name!=NULL && strcmp(name,"finalize")==0 ) { |
|
1989 |
return JNI_TRUE; |
|
1990 |
} |
|
1991 |
return JNI_FALSE; |
|
1992 |
} |
|
1993 |
||
1994 |
static int |
|
1995 |
skip_method(CrwClassImage *ci, const char *name, |
|
1996 |
unsigned access_flags, ByteOffset code_len, |
|
1997 |
int system_class, jboolean *pskip_call_return_sites) |
|
1998 |
{ |
|
1999 |
*pskip_call_return_sites = JNI_FALSE; |
|
2000 |
if ( system_class ) { |
|
2001 |
if ( code_len == 1 && is_init_method(name) ) { |
|
2002 |
return JNI_TRUE; |
|
2003 |
} else if ( code_len == 1 && is_finalize_method(name) ) { |
|
2004 |
return JNI_TRUE; |
|
2005 |
} else if ( is_clinit_method(name) ) { |
|
2006 |
return JNI_TRUE; |
|
2007 |
} else if ( ci->is_thread_class && strcmp(name,"currentThread")==0 ) { |
|
2008 |
return JNI_TRUE; |
|
2009 |
} |
|
2010 |
/* |
|
2011 |
if ( access_flags & JVM_ACC_PRIVATE ) { |
|
2012 |
*pskip_call_return_sites = JNI_TRUE; |
|
2013 |
} |
|
2014 |
*/ |
|
2015 |
} |
|
2016 |
return JNI_FALSE; |
|
2017 |
} |
|
2018 |
||
2019 |
/* Process all code attributes */ |
|
2020 |
static void |
|
2021 |
method_write_bytecodes(CrwClassImage *ci, unsigned mnum, unsigned access_flags) |
|
2022 |
{ |
|
2023 |
CrwPosition output_attr_len_position; |
|
2024 |
CrwPosition output_max_stack_position; |
|
2025 |
CrwPosition output_code_len_position; |
|
2026 |
CrwPosition start_of_output_bytecodes; |
|
2027 |
unsigned i; |
|
2028 |
unsigned attr_len; |
|
2029 |
unsigned max_stack; |
|
2030 |
ByteOffset code_len; |
|
2031 |
unsigned attr_count; |
|
2032 |
unsigned new_attr_len; |
|
2033 |
MethodImage * mi; |
|
2034 |
jboolean object_init_method; |
|
2035 |
jboolean skip_call_return_sites; |
|
2036 |
||
2037 |
CRW_ASSERT_CI(ci); |
|
2038 |
||
2039 |
/* Attribute Length */ |
|
2040 |
output_attr_len_position = ci->output_position; |
|
2041 |
attr_len = copyU4(ci); |
|
2042 |
||
2043 |
/* Max Stack */ |
|
2044 |
output_max_stack_position = ci->output_position; |
|
2045 |
max_stack = copyU2(ci); |
|
2046 |
||
2047 |
/* Max Locals */ |
|
2048 |
(void)copyU2(ci); |
|
2049 |
||
2050 |
/* Code Length */ |
|
2051 |
output_code_len_position = ci->output_position; |
|
2052 |
code_len = copyU4(ci); |
|
2053 |
start_of_output_bytecodes = ci->output_position; |
|
2054 |
||
2055 |
/* Some methods should not be instrumented */ |
|
2056 |
object_init_method = JNI_FALSE; |
|
2057 |
skip_call_return_sites = JNI_FALSE; |
|
2058 |
if ( ci->is_object_class && |
|
2059 |
is_init_method(ci->method_name[mnum]) && |
|
2060 |
strcmp(ci->method_descr[mnum],"()V")==0 ) { |
|
2061 |
object_init_method = JNI_TRUE; |
|
2062 |
skip_call_return_sites = JNI_TRUE; |
|
2063 |
} else if ( skip_method(ci, ci->method_name[mnum], access_flags, |
|
2064 |
code_len, ci->system_class, &skip_call_return_sites) ) { |
|
2065 |
/* Copy remainder minus already copied, the U2 max_stack, |
|
2066 |
* U2 max_locals, and U4 code_length fields have already |
|
2067 |
* been processed. |
|
2068 |
*/ |
|
2069 |
copy(ci, attr_len - (2+2+4)); |
|
2070 |
return; |
|
2071 |
} |
|
2072 |
||
2073 |
/* Start Injection */ |
|
2074 |
mi = method_init(ci, mnum, code_len); |
|
2075 |
mi->object_init_method = object_init_method; |
|
2076 |
mi->access_flags = access_flags; |
|
2077 |
mi->skip_call_return_sites = skip_call_return_sites; |
|
2078 |
||
2079 |
/* Save the current position as the start of the input bytecodes */ |
|
2080 |
mi->start_of_input_bytecodes = ci->input_position; |
|
2081 |
||
2082 |
/* The max stack may increase */ |
|
2083 |
mi->max_stack = max_stack; |
|
2084 |
mi->new_max_stack = max_stack; |
|
2085 |
||
2086 |
/* Adjust all code offsets */ |
|
2087 |
method_inject_and_write_code(mi); |
|
2088 |
||
2089 |
/* Fix up code length (save new_code_len for later attribute processing) */ |
|
2090 |
mi->new_code_len = (int)(ci->output_position - start_of_output_bytecodes); |
|
2091 |
random_writeU4(ci, output_code_len_position, mi->new_code_len); |
|
2092 |
||
2093 |
/* Fixup max stack */ |
|
2094 |
CRW_ASSERT(ci, mi->new_max_stack <= 0xFFFF); |
|
2095 |
random_writeU2(ci, output_max_stack_position, mi->new_max_stack); |
|
2096 |
||
2097 |
/* Copy exception table */ |
|
2098 |
method_write_exception_table(mi); |
|
2099 |
||
2100 |
/* Copy code attributes (needs mi->new_code_len) */ |
|
2101 |
attr_count = copyU2(ci); |
|
2102 |
for (i = 0; i < attr_count; ++i) { |
|
2103 |
method_write_code_attribute(mi); |
|
2104 |
} |
|
2105 |
||
2106 |
/* Fix up attribute length */ |
|
2107 |
new_attr_len = (int)(ci->output_position - (output_attr_len_position + 4)); |
|
2108 |
random_writeU4(ci, output_attr_len_position, new_attr_len); |
|
2109 |
||
2110 |
/* Free method data */ |
|
2111 |
method_term(mi); |
|
2112 |
mi = NULL; |
|
2113 |
||
2114 |
} |
|
2115 |
||
2116 |
static void |
|
2117 |
method_write(CrwClassImage *ci, unsigned mnum) |
|
2118 |
{ |
|
2119 |
unsigned i; |
|
2120 |
unsigned access_flags; |
|
2121 |
CrwCpoolIndex name_index; |
|
2122 |
CrwCpoolIndex descr_index; |
|
2123 |
unsigned attr_count; |
|
2124 |
||
2125 |
access_flags = copyU2(ci); |
|
2126 |
name_index = copyU2(ci); |
|
2127 |
ci->method_name[mnum] = cpool_entry(ci, name_index).ptr; |
|
2128 |
descr_index = copyU2(ci); |
|
2129 |
ci->method_descr[mnum] = cpool_entry(ci, descr_index).ptr; |
|
2130 |
attr_count = copyU2(ci); |
|
2131 |
||
2132 |
for (i = 0; i < attr_count; ++i) { |
|
2133 |
CrwCpoolIndex name_index; |
|
2134 |
||
2135 |
name_index = copyU2(ci); |
|
2136 |
if ( attribute_match(ci, name_index, "Code") ) { |
|
2137 |
method_write_bytecodes(ci, mnum, access_flags); |
|
2138 |
} else { |
|
2139 |
unsigned len; |
|
2140 |
len = copyU4(ci); |
|
2141 |
copy(ci, len); |
|
2142 |
} |
|
2143 |
} |
|
2144 |
} |
|
2145 |
||
2146 |
static void |
|
2147 |
method_write_all(CrwClassImage *ci) |
|
2148 |
{ |
|
2149 |
unsigned i; |
|
2150 |
unsigned count; |
|
2151 |
||
2152 |
count = copyU2(ci); |
|
2153 |
ci->method_count = count; |
|
2154 |
if ( count > 0 ) { |
|
2155 |
ci->method_name = (const char **)allocate_clean(ci, count*(int)sizeof(const char*)); |
|
2156 |
ci->method_descr = (const char **)allocate_clean(ci, count*(int)sizeof(const char*)); |
|
2157 |
} |
|
2158 |
||
2159 |
for (i = 0; i < count; ++i) { |
|
2160 |
method_write(ci, i); |
|
2161 |
} |
|
2162 |
||
2163 |
if ( ci->mnum_callback != NULL ) { |
|
2164 |
(*(ci->mnum_callback))(ci->number, ci->method_name, ci->method_descr, |
|
2165 |
count); |
|
2166 |
} |
|
2167 |
} |
|
2168 |
||
2169 |
/* ------------------------------------------------------------------- */ |
|
2170 |
/* Cleanup function. */ |
|
2171 |
||
2172 |
static void |
|
2173 |
cleanup(CrwClassImage *ci) |
|
2174 |
{ |
|
2175 |
CRW_ASSERT_CI(ci); |
|
2176 |
if ( ci->name != NULL ) { |
|
2177 |
deallocate(ci, (void*)ci->name); |
|
2178 |
ci->name = NULL; |
|
2179 |
} |
|
2180 |
if ( ci->method_name != NULL ) { |
|
2181 |
deallocate(ci, (void*)ci->method_name); |
|
2182 |
ci->method_name = NULL; |
|
2183 |
} |
|
2184 |
if ( ci->method_descr != NULL ) { |
|
2185 |
deallocate(ci, (void*)ci->method_descr); |
|
2186 |
ci->method_descr = NULL; |
|
2187 |
} |
|
2188 |
if ( ci->cpool != NULL ) { |
|
2189 |
CrwCpoolIndex i; |
|
2190 |
for(i=0; i<ci->cpool_count_plus_one; i++) { |
|
2191 |
if ( ci->cpool[i].ptr != NULL ) { |
|
2192 |
deallocate(ci, (void*)(ci->cpool[i].ptr)); |
|
2193 |
ci->cpool[i].ptr = NULL; |
|
2194 |
} |
|
2195 |
} |
|
2196 |
deallocate(ci, (void*)ci->cpool); |
|
2197 |
ci->cpool = NULL; |
|
2198 |
} |
|
2199 |
} |
|
2200 |
||
2201 |
static jboolean |
|
2202 |
skip_class(unsigned access_flags) |
|
2203 |
{ |
|
2204 |
if ( access_flags & JVM_ACC_INTERFACE ) { |
|
2205 |
return JNI_TRUE; |
|
2206 |
} |
|
2207 |
return JNI_FALSE; |
|
2208 |
} |
|
2209 |
||
2210 |
static long |
|
2211 |
inject_class(struct CrwClassImage *ci, |
|
2212 |
int system_class, |
|
2213 |
char* tclass_name, |
|
2214 |
char* tclass_sig, |
|
2215 |
char* call_name, |
|
2216 |
char* call_sig, |
|
2217 |
char* return_name, |
|
2218 |
char* return_sig, |
|
2219 |
char* obj_init_name, |
|
2220 |
char* obj_init_sig, |
|
2221 |
char* newarray_name, |
|
2222 |
char* newarray_sig, |
|
2223 |
unsigned char *buf, |
|
2224 |
long buf_len) |
|
2225 |
{ |
|
2226 |
CrwConstantPoolEntry cs; |
|
2227 |
CrwCpoolIndex this_class; |
|
2228 |
CrwCpoolIndex super_class; |
|
2229 |
unsigned magic; |
|
3067 | 2230 |
unsigned classfileMajorVersion; |
2231 |
unsigned classfileMinorVersion; |
|
2 | 2232 |
unsigned interface_count; |
2233 |
||
2234 |
CRW_ASSERT_CI(ci); |
|
2235 |
CRW_ASSERT(ci, buf!=NULL); |
|
2236 |
CRW_ASSERT(ci, buf_len!=0); |
|
2237 |
||
2238 |
CRW_ASSERT(ci, strchr(tclass_name,'.')==NULL); /* internal qualified name */ |
|
2239 |
||
2240 |
ci->injection_count = 0; |
|
2241 |
ci->system_class = system_class; |
|
2242 |
ci->tclass_name = tclass_name; |
|
2243 |
ci->tclass_sig = tclass_sig; |
|
2244 |
ci->call_name = call_name; |
|
2245 |
ci->call_sig = call_sig; |
|
2246 |
ci->return_name = return_name; |
|
2247 |
ci->return_sig = return_sig; |
|
2248 |
ci->obj_init_name = obj_init_name; |
|
2249 |
ci->obj_init_sig = obj_init_sig; |
|
2250 |
ci->newarray_name = newarray_name; |
|
2251 |
ci->newarray_sig = newarray_sig; |
|
2252 |
ci->output = buf; |
|
2253 |
ci->output_len = buf_len; |
|
2254 |
||
2255 |
magic = copyU4(ci); |
|
2256 |
CRW_ASSERT(ci, magic==0xCAFEBABE); |
|
2257 |
if ( magic != 0xCAFEBABE ) { |
|
2258 |
return (long)0; |
|
2259 |
} |
|
2260 |
||
2261 |
/* minor version number not used */ |
|
3067 | 2262 |
classfileMinorVersion = copyU2(ci); |
2 | 2263 |
/* major version number not used */ |
3067 | 2264 |
classfileMajorVersion = copyU2(ci); |
2265 |
CRW_ASSERT(ci, (classfileMajorVersion <= JVM_CLASSFILE_MAJOR_VERSION) || |
|
2266 |
((classfileMajorVersion == JVM_CLASSFILE_MAJOR_VERSION) && |
|
2267 |
(classfileMinorVersion <= JVM_CLASSFILE_MINOR_VERSION))); |
|
2 | 2268 |
|
2269 |
cpool_setup(ci); |
|
2270 |
||
2271 |
ci->access_flags = copyU2(ci); |
|
2272 |
if ( skip_class(ci->access_flags) ) { |
|
2273 |
return (long)0; |
|
2274 |
} |
|
2275 |
||
2276 |
this_class = copyU2(ci); |
|
2277 |
||
2278 |
cs = cpool_entry(ci, (CrwCpoolIndex)(cpool_entry(ci, this_class).index1)); |
|
2279 |
if ( ci->name == NULL ) { |
|
2280 |
ci->name = duplicate(ci, cs.ptr, cs.len); |
|
2281 |
CRW_ASSERT(ci, strchr(ci->name,'.')==NULL); /* internal qualified name */ |
|
2282 |
} |
|
2283 |
CRW_ASSERT(ci, (int)strlen(ci->name)==cs.len && strncmp(ci->name, cs.ptr, cs.len)==0); |
|
2284 |
||
2285 |
super_class = copyU2(ci); |
|
2286 |
if ( super_class == 0 ) { |
|
2287 |
ci->is_object_class = JNI_TRUE; |
|
2288 |
CRW_ASSERT(ci, strcmp(ci->name,"java/lang/Object")==0); |
|
2289 |
} |
|
2290 |
||
2291 |
interface_count = copyU2(ci); |
|
2292 |
copy(ci, interface_count * 2); |
|
2293 |
||
2294 |
copy_all_fields(ci); |
|
2295 |
||
2296 |
method_write_all(ci); |
|
2297 |
||
2298 |
if ( ci->injection_count == 0 ) { |
|
2299 |
return (long)0; |
|
2300 |
} |
|
2301 |
||
2302 |
copy_attributes(ci); |
|
2303 |
||
2304 |
return (long)ci->output_position; |
|
2305 |
} |
|
2306 |
||
2307 |
/* ------------------------------------------------------------------- */ |
|
2308 |
/* Exported interfaces */ |
|
2309 |
||
2310 |
JNIEXPORT void JNICALL |
|
2311 |
java_crw_demo(unsigned class_number, |
|
2312 |
const char *name, |
|
2313 |
const unsigned char *file_image, |
|
2314 |
long file_len, |
|
2315 |
int system_class, |
|
2316 |
char* tclass_name, /* Name of class that has tracker methods. */ |
|
2317 |
char* tclass_sig, /* Signature of tclass */ |
|
2318 |
char* call_name, /* Method name to call at offset 0 */ |
|
2319 |
char* call_sig, /* Signature of this method */ |
|
2320 |
char* return_name, /* Method name to call before any return */ |
|
2321 |
char* return_sig, /* Signature of this method */ |
|
2322 |
char* obj_init_name, /* Method name to call in Object <init> */ |
|
2323 |
char* obj_init_sig, /* Signature of this method */ |
|
2324 |
char* newarray_name, /* Method name to call after newarray opcodes */ |
|
2325 |
char* newarray_sig, /* Signature of this method */ |
|
2326 |
unsigned char **pnew_file_image, |
|
2327 |
long *pnew_file_len, |
|
2328 |
FatalErrorHandler fatal_error_handler, |
|
2329 |
MethodNumberRegister mnum_callback) |
|
2330 |
{ |
|
2331 |
CrwClassImage ci; |
|
2332 |
long max_length; |
|
2333 |
long new_length; |
|
2334 |
void *new_image; |
|
2335 |
int len; |
|
2336 |
||
2337 |
/* Initial setup of the CrwClassImage structure */ |
|
2338 |
(void)memset(&ci, 0, (int)sizeof(CrwClassImage)); |
|
2339 |
ci.fatal_error_handler = fatal_error_handler; |
|
2340 |
ci.mnum_callback = mnum_callback; |
|
2341 |
||
2342 |
/* Do some interface error checks */ |
|
2343 |
if ( pnew_file_image==NULL ) { |
|
2344 |
CRW_FATAL(&ci, "pnew_file_image==NULL"); |
|
2345 |
} |
|
2346 |
if ( pnew_file_len==NULL ) { |
|
2347 |
CRW_FATAL(&ci, "pnew_file_len==NULL"); |
|
2348 |
} |
|
2349 |
||
2350 |
/* No file length means do nothing */ |
|
2351 |
*pnew_file_image = NULL; |
|
2352 |
*pnew_file_len = 0; |
|
2353 |
if ( file_len==0 ) { |
|
2354 |
return; |
|
2355 |
} |
|
2356 |
||
2357 |
/* Do some more interface error checks */ |
|
2358 |
if ( file_image == NULL ) { |
|
2359 |
CRW_FATAL(&ci, "file_image == NULL"); |
|
2360 |
} |
|
2361 |
if ( file_len < 0 ) { |
|
2362 |
CRW_FATAL(&ci, "file_len < 0"); |
|
2363 |
} |
|
2364 |
if ( system_class != 0 && system_class != 1 ) { |
|
2365 |
CRW_FATAL(&ci, "system_class is not 0 or 1"); |
|
2366 |
} |
|
2367 |
if ( tclass_name == NULL ) { |
|
2368 |
CRW_FATAL(&ci, "tclass_name == NULL"); |
|
2369 |
} |
|
2370 |
if ( tclass_sig == NULL || tclass_sig[0]!='L' ) { |
|
2371 |
CRW_FATAL(&ci, "tclass_sig is not a valid class signature"); |
|
2372 |
} |
|
2373 |
len = (int)strlen(tclass_sig); |
|
2374 |
if ( tclass_sig[len-1]!=';' ) { |
|
2375 |
CRW_FATAL(&ci, "tclass_sig is not a valid class signature"); |
|
2376 |
} |
|
2377 |
if ( call_name != NULL ) { |
|
2378 |
if ( call_sig == NULL || strcmp(call_sig, "(II)V") != 0 ) { |
|
2379 |
CRW_FATAL(&ci, "call_sig is not (II)V"); |
|
2380 |
} |
|
2381 |
} |
|
2382 |
if ( return_name != NULL ) { |
|
2383 |
if ( return_sig == NULL || strcmp(return_sig, "(II)V") != 0 ) { |
|
2384 |
CRW_FATAL(&ci, "return_sig is not (II)V"); |
|
2385 |
} |
|
2386 |
} |
|
2387 |
if ( obj_init_name != NULL ) { |
|
2388 |
if ( obj_init_sig == NULL || strcmp(obj_init_sig, "(Ljava/lang/Object;)V") != 0 ) { |
|
2389 |
CRW_FATAL(&ci, "obj_init_sig is not (Ljava/lang/Object;)V"); |
|
2390 |
} |
|
2391 |
} |
|
2392 |
if ( newarray_name != NULL ) { |
|
2393 |
if ( newarray_sig == NULL || strcmp(newarray_sig, "(Ljava/lang/Object;)V") != 0 ) { |
|
2394 |
CRW_FATAL(&ci, "newarray_sig is not (Ljava/lang/Object;)V"); |
|
2395 |
} |
|
2396 |
} |
|
2397 |
||
2398 |
/* Finish setup the CrwClassImage structure */ |
|
2399 |
ci.is_thread_class = JNI_FALSE; |
|
2400 |
if ( name != NULL ) { |
|
2401 |
CRW_ASSERT(&ci, strchr(name,'.')==NULL); /* internal qualified name */ |
|
2402 |
||
2403 |
ci.name = duplicate(&ci, name, (int)strlen(name)); |
|
2404 |
if ( strcmp(name, "java/lang/Thread")==0 ) { |
|
2405 |
ci.is_thread_class = JNI_TRUE; |
|
2406 |
} |
|
2407 |
} |
|
2408 |
ci.number = class_number; |
|
2409 |
ci.input = file_image; |
|
2410 |
ci.input_len = file_len; |
|
2411 |
||
2412 |
/* Do the injection */ |
|
2413 |
max_length = file_len*2 + 512; /* Twice as big + 512 */ |
|
2414 |
new_image = allocate(&ci, (int)max_length); |
|
2415 |
new_length = inject_class(&ci, |
|
2416 |
system_class, |
|
2417 |
tclass_name, |
|
2418 |
tclass_sig, |
|
2419 |
call_name, |
|
2420 |
call_sig, |
|
2421 |
return_name, |
|
2422 |
return_sig, |
|
2423 |
obj_init_name, |
|
2424 |
obj_init_sig, |
|
2425 |
newarray_name, |
|
2426 |
newarray_sig, |
|
2427 |
new_image, |
|
2428 |
max_length); |
|
2429 |
||
2430 |
/* Dispose or shrink the space to be returned. */ |
|
2431 |
if ( new_length == 0 ) { |
|
2432 |
deallocate(&ci, (void*)new_image); |
|
2433 |
new_image = NULL; |
|
2434 |
} else { |
|
2435 |
new_image = (void*)reallocate(&ci, (void*)new_image, (int)new_length); |
|
2436 |
} |
|
2437 |
||
2438 |
/* Return the new class image */ |
|
2439 |
*pnew_file_image = (unsigned char *)new_image; |
|
2440 |
*pnew_file_len = (long)new_length; |
|
2441 |
||
2442 |
/* Cleanup before we leave. */ |
|
2443 |
cleanup(&ci); |
|
2444 |
} |
|
2445 |
||
2446 |
/* Return the classname for this class which is inside the classfile image. */ |
|
2447 |
JNIEXPORT char * JNICALL |
|
2448 |
java_crw_demo_classname(const unsigned char *file_image, long file_len, |
|
2449 |
FatalErrorHandler fatal_error_handler) |
|
2450 |
{ |
|
2451 |
CrwClassImage ci; |
|
2452 |
CrwConstantPoolEntry cs; |
|
2453 |
CrwCpoolIndex this_class; |
|
2454 |
unsigned magic; |
|
2455 |
char * name; |
|
2456 |
||
2457 |
name = NULL; |
|
2458 |
||
2459 |
if ( file_len==0 || file_image==NULL ) { |
|
2460 |
return name; |
|
2461 |
} |
|
2462 |
||
2463 |
/* The only fields we need filled in are the image pointer and the error |
|
2464 |
* handler. |
|
2465 |
* By not adding an output buffer pointer, no output is created. |
|
2466 |
*/ |
|
2467 |
(void)memset(&ci, 0, (int)sizeof(CrwClassImage)); |
|
2468 |
ci.input = file_image; |
|
2469 |
ci.input_len = file_len; |
|
2470 |
ci.fatal_error_handler = fatal_error_handler; |
|
2471 |
||
2472 |
/* Read out the bytes from the classfile image */ |
|
2473 |
||
2474 |
magic = readU4(&ci); /* magic number */ |
|
2475 |
CRW_ASSERT(&ci, magic==0xCAFEBABE); |
|
2476 |
if ( magic != 0xCAFEBABE ) { |
|
2477 |
return name; |
|
2478 |
} |
|
2479 |
(void)readU2(&ci); /* minor version number */ |
|
2480 |
(void)readU2(&ci); /* major version number */ |
|
2481 |
||
2482 |
/* Read in constant pool. Since no output setup, writes are NOP's */ |
|
2483 |
cpool_setup(&ci); |
|
2484 |
||
2485 |
(void)readU2(&ci); /* access flags */ |
|
2486 |
this_class = readU2(&ci); /* 'this' class */ |
|
2487 |
||
2488 |
/* Get 'this' constant pool entry */ |
|
2489 |
cs = cpool_entry(&ci, (CrwCpoolIndex)(cpool_entry(&ci, this_class).index1)); |
|
2490 |
||
2491 |
/* Duplicate the name */ |
|
2492 |
name = (char *)duplicate(&ci, cs.ptr, cs.len); |
|
2493 |
||
2494 |
/* Cleanup before we leave. */ |
|
2495 |
cleanup(&ci); |
|
2496 |
||
2497 |
/* Return malloc space */ |
|
2498 |
return name; |
|
2499 |
} |