Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/instrument/InvocationAdapter.c
38767 views
1
/*
2
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/*
27
* Copyright 2003 Wily Technology, Inc.
28
*/
29
30
#include <string.h>
31
#include <stdlib.h>
32
33
#include "jni.h"
34
35
#include "Utilities.h"
36
#include "JPLISAssert.h"
37
#include "JPLISAgent.h"
38
#include "JavaExceptions.h"
39
40
#include "EncodingSupport.h"
41
#include "FileSystemSupport.h"
42
#include "JarFacade.h"
43
#include "PathCharsValidator.h"
44
45
/**
46
* This module contains the direct interface points with the JVMTI.
47
* The OnLoad handler is here, along with the various event handlers.
48
*/
49
50
static int
51
appendClassPath(JPLISAgent* agent,
52
const char* jarfile);
53
54
static void
55
appendBootClassPath(JPLISAgent* agent,
56
const char* jarfile,
57
const char* pathList);
58
59
60
/*
61
* Parse -javaagent tail, of the form name[=options], into name
62
* and options. Returned values are heap allocated and options maybe
63
* NULL. Returns 0 if parse succeeds, -1 if allocation fails.
64
*/
65
static int
66
parseArgumentTail(char* tail, char** name, char** options) {
67
int len;
68
char* pos;
69
70
pos = strchr(tail, '=');
71
len = (pos == NULL) ? (int)strlen(tail) : (int)(pos - tail);
72
73
*name = (char*)malloc(len+1);
74
if (*name == NULL) {
75
return -1;
76
}
77
memcpy(*name, tail, len);
78
(*name)[len] = '\0';
79
80
if (pos == NULL) {
81
*options = NULL;
82
} else {
83
char * str = (char*)malloc( (int)strlen(pos + 1) + 1 );
84
if (str == NULL) {
85
free(*name);
86
return -1;
87
}
88
strcpy(str, pos +1);
89
*options = str;
90
}
91
return 0;
92
}
93
94
/*
95
* Get the value of an attribute in an attribute list. Returns NULL
96
* if attribute not found.
97
*/
98
jboolean
99
getBooleanAttribute(const jarAttribute* attributes, const char* name) {
100
char* attributeValue = getAttribute(attributes, name);
101
return attributeValue != NULL && strcasecmp(attributeValue, "true") == 0;
102
}
103
104
/*
105
* Parse any capability settings in the JAR manifest and
106
* convert them to JVM TI capabilities.
107
*/
108
void
109
convertCapabilityAtrributes(const jarAttribute* attributes, JPLISAgent* agent) {
110
/* set redefineClasses capability */
111
if (getBooleanAttribute(attributes, "Can-Redefine-Classes")) {
112
addRedefineClassesCapability(agent);
113
}
114
115
/* create an environment which has the retransformClasses capability */
116
if (getBooleanAttribute(attributes, "Can-Retransform-Classes")) {
117
retransformableEnvironment(agent);
118
}
119
120
/* set setNativeMethodPrefix capability */
121
if (getBooleanAttribute(attributes, "Can-Set-Native-Method-Prefix")) {
122
addNativeMethodPrefixCapability(agent);
123
}
124
125
/* for retransformClasses testing, set capability to use original method order */
126
if (getBooleanAttribute(attributes, "Can-Maintain-Original-Method-Order")) {
127
addOriginalMethodOrderCapability(agent);
128
}
129
}
130
131
/*
132
* This will be called once for every -javaagent on the command line.
133
* Each call to Agent_OnLoad will create its own agent and agent data.
134
*
135
* The argument tail string provided to Agent_OnLoad will be of form
136
* <jarfile>[=<options>]. The tail string is split into the jarfile and
137
* options components. The jarfile manifest is parsed and the value of the
138
* Premain-Class attribute will become the agent's premain class. The jar
139
* file is then added to the system class path, and if the Boot-Class-Path
140
* attribute is present then all relative URLs in the value are processed
141
* to create boot class path segments to append to the boot class path.
142
*/
143
JNIEXPORT jint JNICALL
144
Agent_OnLoad(JavaVM *vm, char *tail, void * reserved) {
145
JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;
146
jint result = JNI_OK;
147
JPLISAgent * agent = NULL;
148
149
initerror = createNewJPLISAgent(vm, &agent);
150
if ( initerror == JPLIS_INIT_ERROR_NONE ) {
151
int oldLen, newLen;
152
char * jarfile;
153
char * options;
154
jarAttribute* attributes;
155
char * premainClass;
156
char * agentClass;
157
char * bootClassPath;
158
159
/*
160
* Parse <jarfile>[=options] into jarfile and options
161
*/
162
if (parseArgumentTail(tail, &jarfile, &options) != 0) {
163
fprintf(stderr, "-javaagent: memory allocation failure.\n");
164
return JNI_ERR;
165
}
166
167
/*
168
* Agent_OnLoad is specified to provide the agent options
169
* argument tail in modified UTF8. However for 1.5.0 this is
170
* actually in the platform encoding - see 5049313.
171
*
172
* Open zip/jar file and parse archive. If can't be opened or
173
* not a zip file return error. Also if Premain-Class attribute
174
* isn't present we return an error.
175
*/
176
attributes = readAttributes(jarfile);
177
if (attributes == NULL) {
178
fprintf(stderr, "Error opening zip file or JAR manifest missing : %s\n", jarfile);
179
free(jarfile);
180
if (options != NULL) free(options);
181
return JNI_ERR;
182
}
183
184
premainClass = getAttribute(attributes, "Premain-Class");
185
if (premainClass == NULL) {
186
fprintf(stderr, "Failed to find Premain-Class manifest attribute in %s\n",
187
jarfile);
188
free(jarfile);
189
if (options != NULL) free(options);
190
freeAttributes(attributes);
191
return JNI_ERR;
192
}
193
194
/*
195
* Add to the jarfile
196
*/
197
appendClassPath(agent, jarfile);
198
199
/*
200
* The value of the Premain-Class attribute becomes the agent
201
* class name. The manifest is in UTF8 so need to convert to
202
* modified UTF8 (see JNI spec).
203
*/
204
oldLen = (int)strlen(premainClass);
205
newLen = modifiedUtf8LengthOfUtf8(premainClass, oldLen);
206
/*
207
* According to JVMS class name is represented as CONSTANT_Utf8_info,
208
* so its length is u2 (i.e. must be <= 0xFFFF).
209
* Negative oldLen or newLen means we got signed integer overflow
210
* (modifiedUtf8LengthOfUtf8 returns negative value if oldLen is negative).
211
*/
212
if (oldLen < 0 || newLen < 0 || newLen > 0xFFFF) {
213
fprintf(stderr, "-javaagent: Premain-Class value is too big\n");
214
free(jarfile);
215
if (options != NULL) free(options);
216
freeAttributes(attributes);
217
return JNI_ERR;
218
}
219
if (newLen == oldLen) {
220
premainClass = strdup(premainClass);
221
} else {
222
char* str = (char*)malloc( newLen+1 );
223
if (str != NULL) {
224
convertUtf8ToModifiedUtf8(premainClass, oldLen, str, newLen);
225
}
226
premainClass = str;
227
}
228
if (premainClass == NULL) {
229
fprintf(stderr, "-javaagent: memory allocation failed\n");
230
free(jarfile);
231
if (options != NULL) free(options);
232
freeAttributes(attributes);
233
return JNI_ERR;
234
}
235
236
/*
237
* If the Boot-Class-Path attribute is specified then we process
238
* each relative URL and add it to the bootclasspath.
239
*/
240
bootClassPath = getAttribute(attributes, "Boot-Class-Path");
241
if (bootClassPath != NULL) {
242
appendBootClassPath(agent, jarfile, bootClassPath);
243
}
244
245
/*
246
* Convert JAR attributes into agent capabilities
247
*/
248
convertCapabilityAtrributes(attributes, agent);
249
250
/*
251
* Track (record) the agent class name and options data
252
*/
253
initerror = recordCommandLineData(agent, premainClass, options);
254
255
/*
256
* Clean-up
257
*/
258
free(jarfile);
259
if (options != NULL) free(options);
260
freeAttributes(attributes);
261
free(premainClass);
262
}
263
264
switch (initerror) {
265
case JPLIS_INIT_ERROR_NONE:
266
result = JNI_OK;
267
break;
268
case JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT:
269
result = JNI_ERR;
270
fprintf(stderr, "java.lang.instrument/-javaagent: cannot create native agent.\n");
271
break;
272
case JPLIS_INIT_ERROR_FAILURE:
273
result = JNI_ERR;
274
fprintf(stderr, "java.lang.instrument/-javaagent: initialization of native agent failed.\n");
275
break;
276
case JPLIS_INIT_ERROR_ALLOCATION_FAILURE:
277
result = JNI_ERR;
278
fprintf(stderr, "java.lang.instrument/-javaagent: allocation failure.\n");
279
break;
280
case JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED:
281
result = JNI_ERR;
282
fprintf(stderr, "-javaagent: agent class not specified.\n");
283
break;
284
default:
285
result = JNI_ERR;
286
fprintf(stderr, "java.lang.instrument/-javaagent: unknown error\n");
287
break;
288
}
289
return result;
290
}
291
292
/*
293
* Agent_OnAttach returns a jint. 0/JNI_OK indicates success and non-0
294
* indicates an error. To allow the attach mechanism throw an
295
* AgentInitializationException with a reasonable exception message we define
296
* a few specific errors here.
297
*/
298
#define AGENT_ERROR_BADJAR ((jint)100) /* Agent JAR not found or no Agent-Class attribute */
299
#define AGENT_ERROR_NOTONCP ((jint)101) /* Unable to add JAR file to system class path */
300
#define AGENT_ERROR_STARTFAIL ((jint)102) /* No agentmain method or agentmain failed */
301
302
/*
303
* This will be called once each time a tool attaches to the VM and loads
304
* the JPLIS library.
305
*/
306
JNIEXPORT jint JNICALL
307
Agent_OnAttach(JavaVM* vm, char *args, void * reserved) {
308
JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;
309
jint result = JNI_OK;
310
JPLISAgent * agent = NULL;
311
JNIEnv * jni_env = NULL;
312
313
/*
314
* Need JNIEnv - guaranteed to be called from thread that is already
315
* attached to VM
316
*/
317
result = (*vm)->GetEnv(vm, (void**)&jni_env, JNI_VERSION_1_2);
318
jplis_assert(result==JNI_OK);
319
320
initerror = createNewJPLISAgent(vm, &agent);
321
if ( initerror == JPLIS_INIT_ERROR_NONE ) {
322
int oldLen, newLen;
323
char * jarfile;
324
char * options;
325
jarAttribute* attributes;
326
char * agentClass;
327
char * bootClassPath;
328
jboolean success;
329
330
/*
331
* Parse <jarfile>[=options] into jarfile and options
332
*/
333
if (parseArgumentTail(args, &jarfile, &options) != 0) {
334
return JNI_ENOMEM;
335
}
336
337
/*
338
* Open the JAR file and parse the manifest
339
*/
340
attributes = readAttributes( jarfile );
341
if (attributes == NULL) {
342
fprintf(stderr, "Error opening zip file or JAR manifest missing: %s\n", jarfile);
343
free(jarfile);
344
if (options != NULL) free(options);
345
return AGENT_ERROR_BADJAR;
346
}
347
348
agentClass = getAttribute(attributes, "Agent-Class");
349
if (agentClass == NULL) {
350
fprintf(stderr, "Failed to find Agent-Class manifest attribute from %s\n",
351
jarfile);
352
free(jarfile);
353
if (options != NULL) free(options);
354
freeAttributes(attributes);
355
return AGENT_ERROR_BADJAR;
356
}
357
358
/*
359
* Add the jarfile to the system class path
360
*/
361
if (appendClassPath(agent, jarfile)) {
362
fprintf(stderr, "Unable to add %s to system class path "
363
"- not supported by system class loader or configuration error!\n",
364
jarfile);
365
free(jarfile);
366
if (options != NULL) free(options);
367
freeAttributes(attributes);
368
return AGENT_ERROR_NOTONCP;
369
}
370
371
/*
372
* The value of the Agent-Class attribute becomes the agent
373
* class name. The manifest is in UTF8 so need to convert to
374
* modified UTF8 (see JNI spec).
375
*/
376
oldLen = strlen(agentClass);
377
newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen);
378
/*
379
* According to JVMS class name is represented as CONSTANT_Utf8_info,
380
* so its length is u2 (i.e. must be <= 0xFFFF).
381
* Negative oldLen or newLen means we got signed integer overflow
382
* (modifiedUtf8LengthOfUtf8 returns negative value if oldLen is negative).
383
*/
384
if (oldLen < 0 || newLen < 0 || newLen > 0xFFFF) {
385
fprintf(stderr, "Agent-Class value is too big\n");
386
free(jarfile);
387
if (options != NULL) free(options);
388
freeAttributes(attributes);
389
return AGENT_ERROR_BADJAR;
390
}
391
if (newLen == oldLen) {
392
agentClass = strdup(agentClass);
393
} else {
394
char* str = (char*)malloc( newLen+1 );
395
if (str != NULL) {
396
convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen);
397
}
398
agentClass = str;
399
}
400
if (agentClass == NULL) {
401
free(jarfile);
402
if (options != NULL) free(options);
403
freeAttributes(attributes);
404
return JNI_ENOMEM;
405
}
406
407
/*
408
* If the Boot-Class-Path attribute is specified then we process
409
* each URL - in the live phase only JAR files will be added.
410
*/
411
bootClassPath = getAttribute(attributes, "Boot-Class-Path");
412
if (bootClassPath != NULL) {
413
appendBootClassPath(agent, jarfile, bootClassPath);
414
}
415
416
/*
417
* Convert JAR attributes into agent capabilities
418
*/
419
convertCapabilityAtrributes(attributes, agent);
420
421
/*
422
* Create the java.lang.instrument.Instrumentation instance
423
*/
424
success = createInstrumentationImpl(jni_env, agent);
425
jplis_assert(success);
426
427
/*
428
* Turn on the ClassFileLoadHook.
429
*/
430
if (success) {
431
success = setLivePhaseEventHandlers(agent);
432
jplis_assert(success);
433
}
434
435
/*
436
* Start the agent
437
*/
438
if (success) {
439
success = startJavaAgent(agent,
440
jni_env,
441
agentClass,
442
options,
443
agent->mAgentmainCaller);
444
}
445
446
if (!success) {
447
fprintf(stderr, "Agent failed to start!\n");
448
result = AGENT_ERROR_STARTFAIL;
449
}
450
451
/*
452
* Clean-up
453
*/
454
free(jarfile);
455
if (options != NULL) free(options);
456
free(agentClass);
457
freeAttributes(attributes);
458
}
459
460
return result;
461
}
462
463
464
JNIEXPORT void JNICALL
465
Agent_OnUnload(JavaVM *vm) {
466
}
467
468
469
/*
470
* JVMTI callback support
471
*
472
* We have two "stages" of callback support.
473
* At OnLoad time, we install a VMInit handler.
474
* When the VMInit handler runs, we remove the VMInit handler and install a
475
* ClassFileLoadHook handler.
476
*/
477
478
void JNICALL
479
eventHandlerVMInit( jvmtiEnv * jvmtienv,
480
JNIEnv * jnienv,
481
jthread thread) {
482
JPLISEnvironment * environment = NULL;
483
jboolean success = JNI_FALSE;
484
485
environment = getJPLISEnvironment(jvmtienv);
486
487
/* process the premain calls on the all the JPL agents */
488
if ( environment != NULL ) {
489
jthrowable outstandingException = preserveThrowable(jnienv);
490
success = processJavaStart( environment->mAgent,
491
jnienv);
492
restoreThrowable(jnienv, outstandingException);
493
}
494
495
/* if we fail to start cleanly, bring down the JVM */
496
if ( !success ) {
497
abortJVM(jnienv, JPLIS_ERRORMESSAGE_CANNOTSTART);
498
}
499
}
500
501
void JNICALL
502
eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv,
503
JNIEnv * jnienv,
504
jclass class_being_redefined,
505
jobject loader,
506
const char* name,
507
jobject protectionDomain,
508
jint class_data_len,
509
const unsigned char* class_data,
510
jint* new_class_data_len,
511
unsigned char** new_class_data) {
512
JPLISEnvironment * environment = NULL;
513
514
environment = getJPLISEnvironment(jvmtienv);
515
516
/* if something is internally inconsistent (no agent), just silently return without touching the buffer */
517
if ( environment != NULL ) {
518
jthrowable outstandingException = preserveThrowable(jnienv);
519
transformClassFile( environment->mAgent,
520
jnienv,
521
loader,
522
name,
523
class_being_redefined,
524
protectionDomain,
525
class_data_len,
526
class_data,
527
new_class_data_len,
528
new_class_data,
529
environment->mIsRetransformer);
530
restoreThrowable(jnienv, outstandingException);
531
}
532
}
533
534
535
536
537
/*
538
* URLs in Boot-Class-Path attributes are separated by one or more spaces.
539
* This function splits the attribute value into a list of path segments.
540
* The attribute value is in UTF8 but cannot contain NUL. Also non US-ASCII
541
* characters must be escaped (URI syntax) so safe to iterate through the
542
* value as a C string.
543
*/
544
static void
545
splitPathList(const char* str, int* pathCount, char*** paths) {
546
int count = 0;
547
char** segments = NULL;
548
char* c = (char*) str;
549
while (*c != '\0') {
550
while (*c == ' ') c++; /* skip leading spaces */
551
if (*c == '\0') {
552
break;
553
}
554
if (segments == NULL) {
555
segments = (char**)malloc( sizeof(char**) );
556
} else {
557
segments = (char**)realloc( segments, (count+1)*sizeof(char**) );
558
}
559
jplis_assert(segments != (char**)NULL);
560
segments[count++] = c;
561
c = strchr(c, ' ');
562
if (c == NULL) {
563
break;
564
}
565
*c = '\0';
566
c++;
567
}
568
*pathCount = count;
569
*paths = segments;
570
}
571
572
573
/* URI path decoding - ported from src/share/classes/java/net/URI.java */
574
575
static int
576
decodeNibble(char c) {
577
if ((c >= '0') && (c <= '9'))
578
return c - '0';
579
if ((c >= 'a') && (c <= 'f'))
580
return c - 'a' + 10;
581
if ((c >= 'A') && (c <= 'F'))
582
return c - 'A' + 10;
583
return -1;
584
}
585
586
static int
587
decodeByte(char c1, char c2) {
588
return (((decodeNibble(c1) & 0xf) << 4) | ((decodeNibble(c2) & 0xf) << 0));
589
}
590
591
/*
592
* Evaluates all escapes in s. Assumes that escapes are well-formed
593
* syntactically, i.e., of the form %XX.
594
* If the path does not require decoding the the original path is
595
* returned. Otherwise the decoded path (heap allocated) is returned,
596
* along with the length of the decoded path. Note that the return
597
* string will not be null terminated after decoding.
598
*/
599
static
600
char *decodePath(const char *s, int* decodedLen) {
601
int n;
602
char *result;
603
char *resultp;
604
int c;
605
int i;
606
607
n = (int)strlen(s);
608
if (n == 0) {
609
*decodedLen = 0;
610
return (char*)s;
611
}
612
if (strchr(s, '%') == NULL) {
613
*decodedLen = n;
614
return (char*)s; /* no escapes, we are done */
615
}
616
617
resultp = result = calloc(n+1, 1);
618
c = s[0];
619
for (i = 0; i < n;) {
620
if (c != '%') {
621
*resultp++ = c;
622
if (++i >= n)
623
break;
624
c = s[i];
625
continue;
626
}
627
for (;;) {
628
char b1 = s[++i];
629
char b2 = s[++i];
630
int decoded = decodeByte(b1, b2);
631
*resultp++ = decoded;
632
if (++i >= n)
633
break;
634
c = s[i];
635
if (c != '%')
636
break;
637
}
638
}
639
*decodedLen = (int)(resultp - result);
640
return result; // not null terminated.
641
}
642
643
/*
644
* Append the given jar file to the system class path. This should succeed in the
645
* onload phase but may fail in the live phase if the system class loader doesn't
646
* support appending to the class path.
647
*/
648
static int
649
appendClassPath( JPLISAgent* agent,
650
const char* jarfile ) {
651
jvmtiEnv* jvmtienv = jvmti(agent);
652
jvmtiError jvmtierr;
653
654
jvmtierr = (*jvmtienv)->AddToSystemClassLoaderSearch(jvmtienv, jarfile);
655
check_phase_ret_1(jvmtierr);
656
657
if (jvmtierr == JVMTI_ERROR_NONE) {
658
return 0;
659
} else {
660
jvmtiPhase phase;
661
jvmtiError err;
662
663
err = (*jvmtienv)->GetPhase(jvmtienv, &phase);
664
/* can be called from any phase */
665
jplis_assert(err == JVMTI_ERROR_NONE);
666
667
if (phase == JVMTI_PHASE_LIVE) {
668
switch (jvmtierr) {
669
case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED :
670
fprintf(stderr, "System class loader does not support adding "
671
"JAR file to system class path during the live phase!\n");
672
break;
673
default:
674
fprintf(stderr, "Unexpected error (%d) returned by "
675
"AddToSystemClassLoaderSearch\n", jvmtierr);
676
break;
677
}
678
return -1;
679
}
680
jplis_assert(0);
681
}
682
return -2;
683
}
684
685
686
/*
687
* res = func, free'ing the previous value of 'res' if function
688
* returns a new result.
689
*/
690
#define TRANSFORM(res,func) { \
691
char* tmp = func; \
692
if (tmp != res) { \
693
free(res); \
694
res = tmp; \
695
} \
696
jplis_assert((void*)res != (void*)NULL); \
697
}
698
699
700
/*
701
* This function takes the value of the Boot-Class-Path attribute,
702
* splits it into the individual path segments, and then combines it
703
* with the path to the jar file to create the path to be added
704
* to the bootclasspath.
705
*
706
* Each individual path segment starts out as a UTF8 string. Additionally
707
* as the path is specified to use URI path syntax all non US-ASCII
708
* characters are escaped. Once the URI path is decoded we get a UTF8
709
* string which must then be converted to the platform encoding (as it
710
* will be combined with the platform path of the jar file). Once
711
* converted it is then normalized (remove duplicate slashes, etc.).
712
* If the resulting path is an absolute path (starts with a slash for
713
* example) then the path will be added to the bootclasspath. Otherwise
714
* if it's not absolute then we get the canoncial path of the agent jar
715
* file and then resolve the path in the context of the base path of
716
* the agent jar.
717
*/
718
static void
719
appendBootClassPath( JPLISAgent* agent,
720
const char* jarfile,
721
const char* pathList ) {
722
char canonicalPath[MAXPATHLEN];
723
char *parent = NULL;
724
int haveBasePath = 0;
725
726
int count, i;
727
char **paths;
728
jvmtiEnv* jvmtienv = jvmti(agent);
729
jvmtiError jvmtierr;
730
731
/*
732
* Split the attribute value into the individual path segments
733
* and process each in sequence
734
*/
735
splitPathList(pathList, &count, &paths);
736
737
for (i=0; i<count; i++) {
738
int len;
739
char* path;
740
char* pos;
741
742
/*
743
* The path segment at this point is a pointer into the attribute
744
* value. As it will go through a number of transformation (tossing away
745
* the previous results as we go along) it make it easier if the path
746
* starts out as a heap allocated string.
747
*/
748
path = strdup(paths[i]);
749
jplis_assert(path != (char*)NULL);
750
751
/*
752
* The attribute is specified to be a list of relative URIs so in theory
753
* there could be a query component - if so, get rid of it.
754
*/
755
pos = strchr(path, '?');
756
if (pos != NULL) {
757
*pos = '\0';
758
}
759
760
/*
761
* Check for characters that are not allowed in the path component of
762
* a URI.
763
*/
764
if (validatePathChars(path)) {
765
fprintf(stderr, "WARNING: illegal character in Boot-Class-Path value: %s\n",
766
path);
767
free(path);
768
continue;
769
}
770
771
772
/*
773
* Next decode any escaped characters. The result is a UTF8 string.
774
*/
775
TRANSFORM(path, decodePath(path,&len));
776
777
/*
778
* Convert to the platform encoding
779
*/
780
{
781
char platform[MAXPATHLEN];
782
int new_len = convertUft8ToPlatformString(path, len, platform, MAXPATHLEN);
783
free(path);
784
if (new_len < 0) {
785
/* bogus value - exceeds maximum path size or unable to convert */
786
continue;
787
}
788
path = strdup(platform);
789
jplis_assert(path != (char*)NULL);
790
}
791
792
/*
793
* Post-process the URI path - needed on Windows to transform
794
* /c:/foo to c:/foo.
795
*/
796
TRANSFORM(path, fromURIPath(path));
797
798
/*
799
* Normalize the path - no duplicate slashes (except UNCs on Windows), trailing
800
* slash removed.
801
*/
802
TRANSFORM(path, normalize(path));
803
804
/*
805
* If the path is an absolute path then add to the bootclassloader
806
* search path. Otherwise we get the canonical path of the agent jar
807
* and then use its base path (directory) to resolve the given path
808
* segment.
809
*
810
* NOTE: JVMTI is specified to use modified UTF8 strings (like JNI).
811
* In 1.5.0 the AddToBootstrapClassLoaderSearch takes a platform string
812
* - see 5049313.
813
*/
814
if (isAbsolute(path)) {
815
jvmtierr = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, path);
816
} else {
817
char* resolved;
818
819
if (!haveBasePath) {
820
if (canonicalize((char*)jarfile, canonicalPath, sizeof(canonicalPath)) != 0) {
821
fprintf(stderr, "WARNING: unable to canonicalize %s\n", jarfile);
822
free(path);
823
continue;
824
}
825
parent = basePath(canonicalPath);
826
jplis_assert(parent != (char*)NULL);
827
haveBasePath = 1;
828
}
829
830
resolved = resolve(parent, path);
831
jvmtierr = (*jvmtienv)->AddToBootstrapClassLoaderSearch(jvmtienv, resolved);
832
}
833
834
/* print warning if boot class path not updated */
835
if (jvmtierr != JVMTI_ERROR_NONE) {
836
check_phase_blob_ret(jvmtierr, free(path));
837
838
fprintf(stderr, "WARNING: %s not added to bootstrap class loader search: ", path);
839
switch (jvmtierr) {
840
case JVMTI_ERROR_ILLEGAL_ARGUMENT :
841
fprintf(stderr, "Illegal argument or not JAR file\n");
842
break;
843
default:
844
fprintf(stderr, "Unexpected error: %d\n", jvmtierr);
845
}
846
}
847
848
/* finished with the path */
849
free(path);
850
}
851
852
853
/* clean-up */
854
if (haveBasePath && parent != canonicalPath) {
855
free(parent);
856
}
857
}
858
859