1 /* Utility routines for finding and reading Java(TM) .class files.
2 Copyright (C) 1996-2013 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>.
19
20 Java and all Java-based marks are trademarks or registered trademarks
21 of Sun Microsystems, Inc. in the United States and other countries.
22 The Free Software Foundation is independent of Sun Microsystems, Inc. */
23
24 /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29
30 #include "jcf.h"
31 #include "tree.h"
32 #include "java-tree.h"
33 #include "hash-table.h"
34 #include <dirent.h>
35
36 #include "zlib.h"
37
38 int
jcf_unexpected_eof(JCF * jcf,int count ATTRIBUTE_UNUSED)39 jcf_unexpected_eof (JCF *jcf, int count ATTRIBUTE_UNUSED)
40 {
41 if (jcf->filename)
42 fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
43 else
44 fprintf (stderr, "Premature end of .class file <stdin>.\n");
45 exit (-1);
46 }
47
48 void
jcf_trim_old_input(JCF * jcf)49 jcf_trim_old_input (JCF *jcf)
50 {
51 int count = jcf->read_ptr - jcf->buffer;
52 if (count > 0)
53 {
54 memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
55 jcf->read_ptr -= count;
56 jcf->read_end -= count;
57 }
58 }
59
60 int
jcf_filbuf_from_stdio(JCF * jcf,int count)61 jcf_filbuf_from_stdio (JCF *jcf, int count)
62 {
63 FILE *file = (FILE*) (jcf->read_state);
64 if (count > jcf->buffer_end - jcf->read_ptr)
65 {
66 JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
67 JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
68 JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
69 JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
70 unsigned char *new_buffer
71 = jcf->buffer == NULL ? XNEWVAR (unsigned char, new_size)
72 : XRESIZEVAR (unsigned char, jcf->buffer, new_size);
73 jcf->buffer = new_buffer;
74 jcf->buffer_end = new_buffer + new_size;
75 jcf->read_ptr = new_buffer + old_read_ptr;
76 jcf->read_end = new_buffer + old_read_end;
77 }
78 count -= jcf->read_end - jcf->read_ptr;
79 if (count <= 0)
80 return 0;
81 if ((int) fread (jcf->read_end, 1, count, file) != count)
82 jcf_unexpected_eof (jcf, count);
83 jcf->read_end += count;
84 return 0;
85 }
86
87 #include "zipfile.h"
88
89 struct ZipFile *SeenZipFiles = NULL;
90
91 /* Open a zip file with the given name, and cache directory and file
92 descriptor. If the file is missing, treat it as an empty archive.
93 Return NULL if the .zip file is malformed.
94 */
95
96 ZipFile *
opendir_in_zip(const char * zipfile,int is_system)97 opendir_in_zip (const char *zipfile, int is_system)
98 {
99 struct ZipFile* zipf;
100 char magic [4];
101 int fd;
102 for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next)
103 {
104 if (strcmp (zipf->name, zipfile) == 0)
105 return zipf;
106 }
107
108 zipf = XNEWVAR (struct ZipFile, sizeof (struct ZipFile) + strlen (zipfile) + 1);
109 zipf->next = SeenZipFiles;
110 zipf->name = (char*)(zipf+1);
111 strcpy (zipf->name, zipfile);
112 fd = open (zipfile, O_RDONLY | O_BINARY);
113 zipf->fd = fd;
114 if (fd < 0)
115 {
116 /* A missing zip file is not considered an error.
117 We may want to re-consider that. FIXME. */
118 zipf->count = 0;
119 zipf->dir_size = 0;
120 zipf->central_directory = NULL;
121 }
122 else
123 {
124 jcf_dependency_add_file (zipfile, is_system);
125 if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
126 {
127 free (zipf);
128 close (fd);
129 return NULL;
130 }
131 lseek (fd, 0L, SEEK_SET);
132 if (read_zip_archive (zipf) != 0)
133 {
134 free (zipf);
135 close (fd);
136 return NULL;
137 }
138 }
139
140 SeenZipFiles = zipf;
141 return zipf;
142 }
143
144 /* Returns:
145 0: OK - zipmember found.
146 -1: Not found.
147 -2: Malformed archive.
148 */
149
150 int
open_in_zip(JCF * jcf,const char * zipfile,const char * zipmember,int is_system)151 open_in_zip (JCF *jcf, const char *zipfile, const char *zipmember,
152 int is_system)
153 {
154 ZipDirectory *zipd;
155 int i, len;
156 ZipFile *zipf = opendir_in_zip (zipfile, is_system);
157
158 if (zipf == NULL)
159 return -2;
160
161 if (!zipmember)
162 return 0;
163
164 len = strlen (zipmember);
165
166 zipd = (struct ZipDirectory*) zipf->central_directory;
167 for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
168 {
169 if (len == zipd->filename_length &&
170 strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
171 {
172 JCF_ZERO (jcf);
173
174 jcf->filename = xstrdup (zipfile);
175 jcf->classname = xstrdup (zipmember);
176 return read_zip_member(jcf, zipd, zipf);
177 }
178 }
179 return -1;
180 }
181
182 /* Read data from zip archive member. */
183
184 int
read_zip_member(JCF * jcf,ZipDirectory * zipd,ZipFile * zipf)185 read_zip_member (JCF *jcf, ZipDirectory *zipd, ZipFile *zipf)
186 {
187 jcf->filbuf = jcf_unexpected_eof;
188 jcf->zipd = zipd;
189
190 if (zipd->compression_method == Z_NO_COMPRESSION)
191 {
192 jcf->buffer = XNEWVEC (unsigned char, zipd->size);
193 jcf->buffer_end = jcf->buffer + zipd->size;
194 jcf->read_ptr = jcf->buffer;
195 jcf->read_end = jcf->buffer_end;
196 if (lseek (zipf->fd, zipd->filestart, 0) < 0
197 || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
198 return -2;
199 }
200 else
201 {
202 char *buffer;
203 z_stream d_stream; /* decompression stream */
204 memset (&d_stream, 0, sizeof (d_stream));
205
206 jcf->buffer = XNEWVEC (unsigned char, zipd->uncompressed_size);
207 d_stream.next_out = jcf->buffer;
208 d_stream.avail_out = zipd->uncompressed_size;
209 jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
210 jcf->read_ptr = jcf->buffer;
211 jcf->read_end = jcf->buffer_end;
212 buffer = XNEWVEC (char, zipd->size);
213 d_stream.next_in = (unsigned char *) buffer;
214 d_stream.avail_in = zipd->size;
215 if (lseek (zipf->fd, zipd->filestart, 0) < 0
216 || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
217 return -2;
218 /* Handle NO_HEADER using undocumented zlib feature.
219 This is a very common hack. */
220 inflateInit2 (&d_stream, -MAX_WBITS);
221 inflate (&d_stream, Z_NO_FLUSH);
222 inflateEnd (&d_stream);
223 free (buffer);
224 }
225
226 return 0;
227 }
228
229 const char *
open_class(const char * filename,JCF * jcf,int fd,const char * dep_name)230 open_class (const char *filename, JCF *jcf, int fd, const char *dep_name)
231 {
232 if (jcf)
233 {
234 struct stat stat_buf;
235 if (fstat (fd, &stat_buf) != 0
236 || ! S_ISREG (stat_buf.st_mode))
237 {
238 perror ("Could not figure length of .class file");
239 return NULL;
240 }
241 if (dep_name != NULL)
242 jcf_dependency_add_file (dep_name, 0);
243 JCF_ZERO (jcf);
244 jcf->buffer = XNEWVEC (unsigned char, stat_buf.st_size);
245 jcf->buffer_end = jcf->buffer + stat_buf.st_size;
246 jcf->read_ptr = jcf->buffer;
247 jcf->read_end = jcf->buffer_end;
248 jcf->read_state = NULL;
249 jcf->filename = xstrdup (filename);
250 if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
251 {
252 perror ("Failed to read .class file");
253 return NULL;
254 }
255 close (fd);
256 jcf->filbuf = jcf_unexpected_eof;
257 }
258 else
259 close (fd);
260 return filename;
261 }
262
263
264 const char *
find_classfile(char * filename,JCF * jcf,const char * dep_name)265 find_classfile (char *filename, JCF *jcf, const char *dep_name)
266 {
267 int fd = open (filename, O_RDONLY | O_BINARY);
268 if (fd < 0)
269 return NULL;
270 return open_class (filename, jcf, fd, dep_name);
271 }
272
273
274 /* Hash table helper. */
275
276 struct charstar_hash : typed_noop_remove <char>
277 {
278 typedef const char value_type;
279 typedef const char compare_type;
280 static inline hashval_t hash (const value_type *candidate);
281 static inline bool equal (const value_type *existing,
282 const compare_type *candidate);
283 };
284
285 inline hashval_t
hash(const value_type * candidate)286 charstar_hash::hash (const value_type *candidate)
287 {
288 return htab_hash_string (candidate);
289 }
290
291 inline bool
equal(const value_type * existing,const compare_type * candidate)292 charstar_hash::equal (const value_type *existing, const compare_type *candidate)
293 {
294 return strcmp (existing, candidate) == 0;
295 }
296
297
298 /* A hash table keeping track of class names that were not found
299 during class lookup. (There is no need to cache the values
300 associated with names that were found; they are saved in
301 IDENTIFIER_CLASS_VALUE.) */
302 static hash_table <charstar_hash> memoized_class_lookups;
303
304 /* Returns a freshly malloc'd string with the fully qualified pathname
305 of the .class file for the class CLASSNAME. CLASSNAME must be
306 allocated in permanent storage; this function may retain a pointer
307 to it. Returns NULL on failure. If JCF != NULL, it is suitably
308 initialized. SOURCE_OK is true if we should also look for .java
309 file. */
310
311 const char *
find_class(const char * classname,int classname_length,JCF * jcf)312 find_class (const char *classname, int classname_length, JCF *jcf)
313 {
314 int fd;
315 int i, k, klass = -1;
316 struct stat class_buf;
317 char *dep_file;
318 void *entry;
319 int buflen;
320 char *buffer;
321 hashval_t hash;
322
323 /* Create the hash table, if it does not already exist. */
324 if (!memoized_class_lookups.is_created ())
325 memoized_class_lookups.create (37);
326
327 /* Loop for this class in the hashtable. If it is present, we've
328 already looked for this class and failed to find it. */
329 hash = charstar_hash::hash (classname);
330 if (memoized_class_lookups.find_with_hash (classname, hash))
331 return NULL;
332
333 /* Allocate and zero out the buffer, since we don't explicitly put a
334 null pointer when we're copying it below. */
335 buflen = jcf_path_max_len () + classname_length + 10;
336 buffer = XNEWVAR (char, buflen);
337 memset (buffer, 0, buflen);
338
339 for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
340 {
341 const char *path_name = jcf_path_name (entry);
342 if (klass != 0)
343 {
344 int dir_len;
345
346 strcpy (buffer, path_name);
347 i = strlen (buffer);
348
349 /* This is right because we know that `.zip' entries will have a
350 trailing slash. See jcf-path.c. */
351 dir_len = i - 1;
352
353 for (k = 0; k < classname_length; k++, i++)
354 {
355 char ch = classname[k];
356 buffer[i] = ch == '.' ? '/' : ch;
357 }
358 strcpy (buffer+i, ".class");
359
360 if (jcf_path_is_zipfile (entry))
361 {
362 int err_code;
363 JCF _jcf;
364 buffer[dir_len] = '\0';
365 SOURCE_FRONTEND_DEBUG
366 (("Trying [...%s]:%s",
367 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
368 buffer+dir_len+1));
369 if (jcf == NULL)
370 jcf = &_jcf;
371 err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
372 jcf_path_is_system (entry));
373 if (err_code == 0)
374 {
375 /* Should we check if .zip is out-of-date wrt .java? */
376 buffer[dir_len] = '(';
377 strcpy (buffer+i, ".class)");
378 if (jcf == &_jcf)
379 JCF_FINISH (jcf);
380 return buffer;
381 }
382 else
383 continue;
384 }
385 klass = stat (buffer, &class_buf);
386 }
387 }
388
389 dep_file = buffer;
390 if (!klass)
391 {
392 SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
393 classname+classname_length-
394 (classname_length <= 30 ?
395 classname_length : 30)));
396 fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY | O_BINARY);
397 if (fd >= 0)
398 goto found;
399 }
400
401 free (buffer);
402
403 /* Remember that this class could not be found so that we do not
404 have to look again. */
405 *memoized_class_lookups.find_slot_with_hash (classname, hash, INSERT)
406 = classname;
407
408 return NULL;
409 found:
410 {
411 const char *const tmp = open_class (buffer, jcf, fd, dep_file);
412 jcf->classname = xstrdup (classname);
413 return tmp;
414 }
415 }
416
417 void
jcf_print_char(FILE * stream,int ch)418 jcf_print_char (FILE *stream, int ch)
419 {
420 switch (ch)
421 {
422 case '\'':
423 case '\\':
424 case '\"':
425 fprintf (stream, "\\%c", ch);
426 break;
427 case '\n':
428 fprintf (stream, "\\n");
429 break;
430 case '\t':
431 fprintf (stream, "\\t");
432 break;
433 case '\r':
434 fprintf (stream, "\\r");
435 break;
436 default:
437 if (ch >= ' ' && ch < 127)
438 putc (ch, stream);
439 else if (ch < 256)
440 fprintf (stream, "\\%03x", ch);
441 else
442 fprintf (stream, "\\u%04x", ch);
443 }
444 }
445
446 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
447
448 void
jcf_print_utf8(FILE * stream,const unsigned char * str,int length)449 jcf_print_utf8 (FILE *stream, const unsigned char *str, int length)
450 {
451 const unsigned char * limit = str + length;
452 while (str < limit)
453 {
454 int ch = UTF8_GET (str, limit);
455 if (ch < 0)
456 {
457 fprintf (stream, "\\<invalid>");
458 return;
459 }
460 jcf_print_char (stream, ch);
461 }
462 }
463
464 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
465
466 void
jcf_print_utf8_replace(FILE * stream,const unsigned char * str,int length,int in_char,int out_char)467 jcf_print_utf8_replace (FILE *stream, const unsigned char *str, int length,
468 int in_char, int out_char)
469 {
470 const unsigned char *limit = str + length;
471 while (str < limit)
472 {
473 int ch = UTF8_GET (str, limit);
474 if (ch < 0)
475 {
476 fprintf (stream, "\\<invalid>");
477 return;
478 }
479 jcf_print_char (stream, ch == in_char ? out_char : ch);
480 }
481 }
482
483 /* Check that all the cross-references in the constant pool are
484 valid. Returns 0 on success.
485 Otherwise, returns the index of the (first) invalid entry.
486 Only checks internal consistency, but does not check that
487 any classes, fields, or methods are valid.*/
488
489 int
verify_constant_pool(JCF * jcf)490 verify_constant_pool (JCF *jcf)
491 {
492 int i, n;
493 for (i = 1; i < JPOOL_SIZE (jcf); i++)
494 {
495 switch (JPOOL_TAG (jcf, i))
496 {
497 case CONSTANT_NameAndType:
498 n = JPOOL_USHORT2 (jcf, i);
499 if (n <= 0 || n >= JPOOL_SIZE(jcf)
500 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
501 return i;
502 /* ... fall through ... */
503 case CONSTANT_Class:
504 case CONSTANT_String:
505 n = JPOOL_USHORT1 (jcf, i);
506 if (n <= 0 || n >= JPOOL_SIZE(jcf)
507 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
508 return i;
509 break;
510 case CONSTANT_Fieldref:
511 case CONSTANT_Methodref:
512 case CONSTANT_InterfaceMethodref:
513 n = JPOOL_USHORT1 (jcf, i);
514 if (n <= 0 || n >= JPOOL_SIZE(jcf)
515 || JPOOL_TAG (jcf, n) != CONSTANT_Class)
516 return i;
517 n = JPOOL_USHORT2 (jcf, i);
518 if (n <= 0 || n >= JPOOL_SIZE(jcf)
519 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
520 return i;
521 break;
522 case CONSTANT_Long:
523 case CONSTANT_Double:
524 i++;
525 break;
526 case CONSTANT_Float:
527 case CONSTANT_Integer:
528 case CONSTANT_Utf8:
529 case CONSTANT_Unicode:
530 break;
531 case CONSTANT_MethodHandle:
532 n = JPOOL_USHORT1 (jcf, i);
533 if (n < 1 || n > 9)
534 return i;
535 n = JPOOL_USHORT2 (jcf, i);
536 if (n <= 0 || n >= JPOOL_SIZE(jcf))
537 return i;
538 break;
539 case CONSTANT_MethodType:
540 n = JPOOL_USHORT1 (jcf, i);
541 if (n <= 0 || n >= JPOOL_SIZE(jcf)
542 || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
543 return i;
544 break;
545 case CONSTANT_InvokeDynamic:
546 n = JPOOL_USHORT2 (jcf, i);
547 if (n <= 0 || n >= JPOOL_SIZE(jcf)
548 || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
549 return i;
550 break;
551 default:
552 return i;
553 }
554 }
555 return 0;
556 }
557
558 void
format_uint(char * buffer,uint64 value,int base)559 format_uint (char *buffer, uint64 value, int base)
560 {
561 #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
562 char buf[WRITE_BUF_SIZE];
563 char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
564 int chars_written;
565 int i;
566
567 /* Now do the actual conversion, placing the result at the *end* of buf. */
568 /* Note this code does not pretend to be optimized. */
569 do {
570 int digit = value % base;
571 static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
572 *--buf_ptr = digit_chars[digit];
573 value /= base;
574 } while (value != 0);
575
576 chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
577 for (i = 0; i < chars_written; i++)
578 buffer[i] = *buf_ptr++;
579 buffer[i] = 0;
580 }
581
582 void
format_int(char * buffer,jlong value,int base)583 format_int (char *buffer, jlong value, int base)
584 {
585 uint64 abs_value;
586 if (value < 0)
587 {
588 abs_value = -(uint64)value;
589 *buffer++ = '-';
590 }
591 else
592 abs_value = (uint64) value;
593 format_uint (buffer, abs_value, base);
594 }
595