36
36
import java .util .regex .Pattern ;
37
37
38
38
import jdk .graal .compiler .code .CompilationResult .CodeAnnotation ;
39
+ import jdk .graal .compiler .core .common .NativeImageSupport ;
40
+ import jdk .graal .compiler .debug .GraalError ;
41
+ import jdk .graal .compiler .debug .TTY ;
39
42
import jdk .graal .compiler .options .Option ;
40
43
import jdk .graal .compiler .options .OptionKey ;
41
44
import jdk .graal .compiler .options .OptionType ;
@@ -72,13 +75,14 @@ static class Options {
72
75
}
73
76
74
77
// cached validity of candidate objdump executables.
75
- private Map <String , Boolean > objdumpCache = new HashMap <>();
78
+ private static final Map <String , Boolean > objdumpCache = new HashMap <>();
76
79
77
80
private static Process createProcess (String [] cmd ) {
78
81
ProcessBuilder pb = new ProcessBuilder (cmd );
79
82
try {
80
83
return pb .start ();
81
84
} catch (IOException e ) {
85
+ TTY .printf ("WARNING: Error executing '%s' (%s)%n" , String .join (" " , cmd ), e );
82
86
}
83
87
return null ;
84
88
}
@@ -90,6 +94,9 @@ public boolean isAvailable(OptionValues options) {
90
94
91
95
@ Override
92
96
public String disassembleCompiledCode (OptionValues options , CodeCacheProvider codeCache , CompilationResult compResult ) {
97
+ if (NativeImageSupport .inRuntimeCode () && !ENABLE_OBJDUMP ) {
98
+ throw new GraalError ("Objdump not available" );
99
+ }
93
100
String objdump = getObjdump (options );
94
101
if (objdump == null ) {
95
102
return null ;
@@ -129,8 +136,7 @@ public String disassembleCompiledCode(OptionValues options, CodeCacheProvider co
129
136
putAnnotation (annotations , a .getPosition (), a .toString ());
130
137
}
131
138
for (Infopoint infopoint : compResult .getInfopoints ()) {
132
- if (infopoint instanceof Call ) {
133
- Call call = (Call ) infopoint ;
139
+ if (infopoint instanceof Call call ) {
134
140
if (call .debugInfo != null ) {
135
141
putAnnotation (annotations , call .pcOffset + call .size , CodeUtil .append (new StringBuilder (100 ), call .debugInfo , slotFormatter ).toString ());
136
142
}
@@ -170,15 +176,14 @@ public String disassembleCompiledCode(OptionValues options, CodeCacheProvider co
170
176
String errLine = ebr .readLine ();
171
177
if (errLine != null ) {
172
178
System .err .println ("Error output from executing: " + CollectionsUtil .mapAndJoin (cmdline , e -> quoteShellArg (String .valueOf (e )), " " ));
173
- System .err .println (errLine );
174
- while ((errLine = ebr .readLine ()) != null ) {
179
+ do {
175
180
System .err .println (errLine );
176
- }
181
+ } while (( errLine = ebr . readLine ()) != null );
177
182
}
178
183
}
179
184
return sb .toString ();
180
185
} catch (IOException e ) {
181
- e .printStackTrace ();
186
+ e .printStackTrace (TTY . out );
182
187
return null ;
183
188
} finally {
184
189
if (tmp != null ) {
@@ -188,9 +193,9 @@ public String disassembleCompiledCode(OptionValues options, CodeCacheProvider co
188
193
}
189
194
190
195
/**
191
- * Pattern for a single shell command argument that does not need to quoted.
196
+ * Pattern for a single shell command argument that does not need to be quoted.
192
197
*/
193
- private static final Pattern SAFE_SHELL_ARG = Pattern .compile ("[A-Za-z0-9@%_\\ -\\ +=:,\\ ./]+" );
198
+ private static final Pattern SAFE_SHELL_ARG = Pattern .compile ("[A-Za-z0-9@%_\\ -+=:,./]+" );
194
199
195
200
/**
196
201
* Reliably quote a string as a single shell command argument.
@@ -207,52 +212,78 @@ public static String quoteShellArg(String arg) {
207
212
return "'" + arg .replace ("'" , "'\" '\" '" ) + "'" ;
208
213
}
209
214
215
+ private static final String ENABLE_OBJDUMP_PROP = "debug.jdk.graal.enableObjdump" ;
216
+
217
+ /**
218
+ * Support for objdump is excluded by default from native images (including libgraal) to reduce
219
+ * the image size. It also reduces security concerns related to running subprocesses.
220
+ *
221
+ * To objdump during development, set the {@value #ENABLE_OBJDUMP_PROP} system property to true
222
+ * when building native images.
223
+ */
224
+ private static final boolean ENABLE_OBJDUMP = Boolean .parseBoolean (GraalServices .getSavedProperty (ENABLE_OBJDUMP_PROP ));
225
+
226
+ private static boolean objdumpUnsupportedWarned ;
227
+
210
228
/**
211
229
* Searches for a valid GNU objdump executable.
212
230
*/
213
- private String getObjdump (OptionValues options ) {
231
+ private static String getObjdump (OptionValues options ) {
214
232
// for security, user must provide the possible objdump locations.
215
233
String candidates = Options .ObjdumpExecutables .getValue (options );
216
234
if (candidates != null && !candidates .isEmpty ()) {
235
+ if (NativeImageSupport .inRuntimeCode () && !ENABLE_OBJDUMP ) {
236
+ if (!objdumpUnsupportedWarned ) {
237
+ // Ignore races or multiple isolates - an extra warning is ok
238
+ objdumpUnsupportedWarned = true ;
239
+ TTY .printf ("WARNING: Objdump not supported as the %s system property was false when building.%n" ,
240
+ ENABLE_OBJDUMP_PROP );
241
+ }
242
+ return null ;
243
+ }
244
+
217
245
for (String candidate : candidates .split ("," )) {
218
- // first checking to see if a cached verdict for this candidate exists.
219
- Boolean cachedQuery = objdumpCache .get (candidate );
220
- if (cachedQuery != null ) {
221
- if (cachedQuery .booleanValue ()) {
222
- return candidate ;
223
- } else {
224
- // this candidate was previously determined to not be acceptable.
225
- continue ;
246
+ synchronized (objdumpCache ) {
247
+ // first checking to see if a cached verdict for this candidate exists.
248
+ Boolean cachedQuery = objdumpCache .get (candidate );
249
+ if (cachedQuery != null ) {
250
+ if (cachedQuery ) {
251
+ return candidate ;
252
+ } else {
253
+ // this candidate was previously determined to not be acceptable.
254
+ continue ;
255
+ }
226
256
}
227
- }
228
- try {
229
257
String [] cmd = {candidate , "--version" };
230
- Process proc = createProcess (cmd );
231
- if (proc == null ) {
232
- // bad candidate.
233
- objdumpCache .put (candidate , Boolean .FALSE );
234
- return null ;
235
- }
236
- InputStream is = proc .getInputStream ();
237
- int exitValue = proc .waitFor ();
238
- if (exitValue == 0 ) {
239
- byte [] buf = new byte [is .available ()];
240
- int pos = 0 ;
241
- while (pos < buf .length ) {
242
- int read = is .read (buf , pos , buf .length - pos );
243
- pos += read ;
258
+ try {
259
+ Process proc = createProcess (cmd );
260
+ if (proc == null ) {
261
+ // bad candidate.
262
+ objdumpCache .put (candidate , Boolean .FALSE );
263
+ return null ;
244
264
}
245
- String output = new String (buf );
246
- if (output .contains ("GNU objdump" )) {
247
- // this candidate meets the criteria.
248
- objdumpCache .put (candidate , Boolean .TRUE );
249
- return candidate ;
265
+ InputStream is = proc .getInputStream ();
266
+ int exitValue = proc .waitFor ();
267
+ if (exitValue == 0 ) {
268
+ byte [] buf = new byte [is .available ()];
269
+ int pos = 0 ;
270
+ while (pos < buf .length ) {
271
+ int read = is .read (buf , pos , buf .length - pos );
272
+ pos += read ;
273
+ }
274
+ String output = new String (buf );
275
+ if (output .contains ("GNU objdump" )) {
276
+ // this candidate meets the criteria.
277
+ objdumpCache .put (candidate , Boolean .TRUE );
278
+ return candidate ;
279
+ }
250
280
}
281
+ } catch (IOException | InterruptedException e ) {
282
+ TTY .printf ("WARNING: Error reading input from '%s' (%s)%n" , String .join (" " , cmd ), e );
251
283
}
252
- } catch (IOException | InterruptedException e ) {
284
+ // bad candidate.
285
+ objdumpCache .put (candidate , Boolean .FALSE );
253
286
}
254
- // bad candidate.
255
- objdumpCache .put (candidate , Boolean .FALSE );
256
287
}
257
288
}
258
289
return null ;
0 commit comments