3636import java .util .regex .Pattern ;
3737
3838import 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 ;
3942import jdk .graal .compiler .options .Option ;
4043import jdk .graal .compiler .options .OptionKey ;
4144import jdk .graal .compiler .options .OptionType ;
@@ -72,13 +75,14 @@ static class Options {
7275 }
7376
7477 // cached validity of candidate objdump executables.
75- private Map <String , Boolean > objdumpCache = new HashMap <>();
78+ private static final Map <String , Boolean > objdumpCache = new HashMap <>();
7679
7780 private static Process createProcess (String [] cmd ) {
7881 ProcessBuilder pb = new ProcessBuilder (cmd );
7982 try {
8083 return pb .start ();
8184 } catch (IOException e ) {
85+ TTY .printf ("WARNING: Error executing '%s' (%s)%n" , String .join (" " , cmd ), e );
8286 }
8387 return null ;
8488 }
@@ -90,6 +94,9 @@ public boolean isAvailable(OptionValues options) {
9094
9195 @ Override
9296 public String disassembleCompiledCode (OptionValues options , CodeCacheProvider codeCache , CompilationResult compResult ) {
97+ if (NativeImageSupport .inRuntimeCode () && !ENABLE_OBJDUMP ) {
98+ throw new GraalError ("Objdump not available" );
99+ }
93100 String objdump = getObjdump (options );
94101 if (objdump == null ) {
95102 return null ;
@@ -129,8 +136,7 @@ public String disassembleCompiledCode(OptionValues options, CodeCacheProvider co
129136 putAnnotation (annotations , a .getPosition (), a .toString ());
130137 }
131138 for (Infopoint infopoint : compResult .getInfopoints ()) {
132- if (infopoint instanceof Call ) {
133- Call call = (Call ) infopoint ;
139+ if (infopoint instanceof Call call ) {
134140 if (call .debugInfo != null ) {
135141 putAnnotation (annotations , call .pcOffset + call .size , CodeUtil .append (new StringBuilder (100 ), call .debugInfo , slotFormatter ).toString ());
136142 }
@@ -170,15 +176,14 @@ public String disassembleCompiledCode(OptionValues options, CodeCacheProvider co
170176 String errLine = ebr .readLine ();
171177 if (errLine != null ) {
172178 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 {
175180 System .err .println (errLine );
176- }
181+ } while (( errLine = ebr . readLine ()) != null );
177182 }
178183 }
179184 return sb .toString ();
180185 } catch (IOException e ) {
181- e .printStackTrace ();
186+ e .printStackTrace (TTY . out );
182187 return null ;
183188 } finally {
184189 if (tmp != null ) {
@@ -188,9 +193,9 @@ public String disassembleCompiledCode(OptionValues options, CodeCacheProvider co
188193 }
189194
190195 /**
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.
192197 */
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@%_\\ -+=:,./]+" );
194199
195200 /**
196201 * Reliably quote a string as a single shell command argument.
@@ -207,52 +212,78 @@ public static String quoteShellArg(String arg) {
207212 return "'" + arg .replace ("'" , "'\" '\" '" ) + "'" ;
208213 }
209214
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+
210228 /**
211229 * Searches for a valid GNU objdump executable.
212230 */
213- private String getObjdump (OptionValues options ) {
231+ private static String getObjdump (OptionValues options ) {
214232 // for security, user must provide the possible objdump locations.
215233 String candidates = Options .ObjdumpExecutables .getValue (options );
216234 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+
217245 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+ }
226256 }
227- }
228- try {
229257 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 ;
244264 }
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+ }
250280 }
281+ } catch (IOException | InterruptedException e ) {
282+ TTY .printf ("WARNING: Error reading input from '%s' (%s)%n" , String .join (" " , cmd ), e );
251283 }
252- } catch (IOException | InterruptedException e ) {
284+ // bad candidate.
285+ objdumpCache .put (candidate , Boolean .FALSE );
253286 }
254- // bad candidate.
255- objdumpCache .put (candidate , Boolean .FALSE );
256287 }
257288 }
258289 return null ;
0 commit comments