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