OpenADFortTk (including Open64 and OpenAnalysis references)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ir_bread.cxx
Go to the documentation of this file.
1 /*
2 
3  Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved.
4 
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of version 2 of the GNU General Public License as
7  published by the Free Software Foundation.
8 
9  This program is distributed in the hope that it would be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13  Further, this software is distributed without any warranty that it is
14  free of the rightful claim of any third person regarding infringement
15  or the like. Any license provided herein, whether implied or
16  otherwise, applies only to this software file. Patent licenses, if
17  any, provided herein do not apply to combinations of this program with
18  other software, or any other product whatsoever.
19 
20  You should have received a copy of the GNU General Public License along
21  with this program; if not, write the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 
24  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky,
25  Mountain View, CA 94043, or:
26 
27  http://www.sgi.com
28 
29  For further information regarding this notice, see:
30 
31  http://oss.sgi.com/projects/GenInfo/NoticeExplan
32 
33 */
34 
35 #ifdef USE_PCH
36 #include "common_com_pch.h"
37 #endif /* USE_PCH */
38 #pragma hdrstop
39 #include <unistd.h> /* for close(), etc. */
40 #include <sys/stat.h> /* for fstat() */
41 #include <sys/mman.h> /* for mmap() */
42 #include <fcntl.h> /* for open() */
43 #include <elf.h> /* Open64 version */
44 #include <sys/elf_whirl.h> /* for WHIRL sections */
45 #include <errno.h> /* for error code */
46 
47 #ifndef USE_STANDARD_TYPES
48 # define USE_STANDARD_TYPES /* override unwanted defines in "defs.h" */
49 #endif
50 
51 #include "defs.h" /* for wn_core.h */
52 #include "alignof.h" /* for ALIGNOF() */
53 #ifdef OWN_ERROR_PACKAGE
54 /* Turn off assertion in the opcode handling routines, we assume the tree
55  * is clean. Also, this removes the dependency on "errors.h", which is not
56  * used by all programs.
57  */
58 #define Is_True(x,y) (0)
59 #define ERRORS_INCLUDED
60 #else
61 #include "erglob.h"
62 #endif
63 #include "errors.h"
64 #include "opcode.h" /* for wn_core.h */
65 #include "mempool.h" /* for MEM_POOL (for maps) */
66 #include "strtab.h" /* for strtab */
67 #include "symtab.h" /* for symtab */
68 #include "const.h" /* for constab */
69 #include "targ_const.h" /* for tcon */
70 #include "config_targ.h" /* for Target_ABI */
71 #include "config_debug.h" /* for ir_version_check */
72 #include "config_elf_targ.h"
73 #include "irbdata.h" /* for init_data */
74 #include "wn_core.h" /* for WN */
75 #include "wn.h" /* for max_region_id */
76 #include "wn_map.h" /* for WN maps */
77 #define USE_DST_INTERNALS
78 #include "dwarf_DST_mem.h" /* for dst */
79 #include "pu_info.h"
80 #include "ir_elf.h"
81 #include "ir_bwrite.h"
82 #include "ir_bcom.h"
83 #include "ir_bread.h"
84 
85 #if defined(BACK_END)
86 #include "xstats.h"
87 #endif
88 #if defined(BACK_END) || defined(BUILD_WNPREFETCH)
89 #include "pf_cg.h"
90 #endif
91 
92 
93 
95 static WN *last_node = NULL;
96 
97 static off_t global_mapped_size;
98 static off_t local_mapped_size;
99 
100 static char file_revision[80]; /* save revision string */
101 
102 
103 #define DOUBLE_ALIGNED(sz) (((sz) % 8) == 0 ? (sz) : (sz)+(8-((sz)%8)))
104 #define ERROR_VALUE -1
105 /* should be under Is_True_On, but we don't use that for ir_reader,
106  * so add another define */
107 
108 #if defined(Is_True_On) || defined(DEBUG_IR)
109 /* to make debugging easier, have all error returns go through this routine */
110 
111 INT
113 {
114  if (verbose_info && last_node != NULL) {
115  printf("last_node at %p, opcode = %s\n",
116  last_node, OPCODE_name(WN_opcode(last_node)));
117  }
118  return ERROR_VALUE;
119 }
120 
121 #define ERROR_RETURN Error_Return_Func()
122 #else
123 #define ERROR_RETURN ERROR_VALUE
124 #endif
125 
126 
127 template <class Shdr>
128 const Shdr*
129 get_section_header (const Shdr* shdr, UINT n, Elf64_Word type, Elf64_Word info)
130 {
131  for (INT i = 1; i < n; ++i) {
132  if (shdr[i].sh_type == type && shdr[i].sh_info == info)
133  return shdr + i;
134  }
135 
136  return NULL;
137 }
138 
140 get_section (void *handle, Elf64_Word type, Elf64_Word info)
141 {
142  if (handle == 0 || handle == (void *)(ERROR_VALUE)) {
143  errno = EINVAL;
144  return OFFSET_AND_SIZE (0, 0);
145  }
146 
147  errno = 0;
148 
149  Elf64_Ehdr *eh = (Elf64_Ehdr *) handle;
150 
151 #ifndef __ALWAYS_USE_64BIT_ELF__
152  if (eh->e_ident[EI_CLASS] == ELFCLASS32) {
153  Elf32_Ehdr* ehdr = (Elf32_Ehdr*) handle;
154  const Elf32_Shdr* shdr = (const Elf32_Shdr *)
155  ((char *) handle + ehdr->e_shoff);
156  shdr = get_section_header (shdr, ehdr->e_shnum, type, info);
157  if (!shdr)
158  return OFFSET_AND_SIZE (0, 0);
159  return OFFSET_AND_SIZE (shdr->sh_offset, shdr->sh_size);
160  } else
161 #endif
162  {
163  const Elf64_Shdr* shdr = (const Elf64_Shdr *)
164  ((char *) handle + eh->e_shoff);
165  shdr = get_section_header (shdr, eh->e_shnum, type, info);
166  if (!shdr)
167  return OFFSET_AND_SIZE (0, 0);
168  return OFFSET_AND_SIZE (shdr->sh_offset, shdr->sh_size);
169  }
170 } /* get_section */
171 
172 
173 /* If the CHECK_INPUT_FILES macro is defined, the binary reader tries to
174  check for offsets that are outside the current (sub)section and for
175  symbol table indices that are outside the valid ranges. To make the
176  reading process as fast as possible, you can leave CHECK_INPUT_FILES
177  undefined. */
178 
179 #if defined(Is_True_On) || defined(DEBUG_IR)
180 #define CHECK_INPUT_FILES
181 #endif
182 
183 #ifdef CHECK_INPUT_FILES
184 
185 #define CONVERT_OFFSET(typ, fld) \
186  if ((INTPTR)(fld) >= size) return ERROR_RETURN; \
187  else (fld) = (typ)(base + (INTPTR)(fld))
188 
189 #else
190 
191 #define CONVERT_OFFSET(typ, fld) \
192  (fld) = (typ)(base + (INTPTR)(fld))
193 
194 #endif // CHECK_INPUT_FILES
195 
196 
197 // read the global symbol table from the file and set up the various global
198 // symtab data structures. try to reuse the mmap'ed memory buffer if
199 // possible (i.e., avoid copying).
200 
201 INT
202 WN_get_global_symtab (void *handle)
203 {
204 
206  if (shdr.offset == 0)
207  return ERROR_RETURN;
208 
209  const char *base = (char *) handle + shdr.offset;
210 
211  const GLOBAL_SYMTAB_HEADER_TABLE *gsymtab =
213 
214  UINT64 size = shdr.size;
215 
216  if (gsymtab->size < sizeof(gsymtab) ||
217  gsymtab->entries < GLOBAL_SYMTAB_TABLES || gsymtab->size > size)
218  return ERROR_RETURN;
219 
220  UINT i;
221  for (i = 0; i < GLOBAL_SYMTAB_TABLES; ++i)
222  if (gsymtab->header[i].offset + gsymtab->header[i].size > size)
223  return ERROR_RETURN;
224 
225  for (i = 0; i < GLOBAL_SYMTAB_TABLES; ++i) {
226  const SYMTAB_HEADER& hdr = gsymtab->header[i];
227  const char *addr = base + hdr.offset;
228 
229  switch (hdr.type) {
230 
231  case SHDR_FILE:
232  File_info = *((FILE_INFO *) addr);
233  break;
234 
235  case SHDR_ST:
237  Transfer ((ST *) addr, hdr.size / hdr.entsize);
238  break;
239 
240  case SHDR_TY:
241  Ty_tab.Transfer ((TY *) addr, hdr.size / hdr.entsize);
242  break;
243 
244  case SHDR_PU:
245  Pu_Table.Transfer ((PU *) addr, hdr.size / hdr.entsize);
246  break;
247 
248  case SHDR_FLD:
249  Fld_Table.Transfer ((FLD *) addr, hdr.size / hdr.entsize);
250  break;
251 
252  case SHDR_ARB:
253  Arb_Table.Transfer ((ARB *) addr, hdr.size / hdr.entsize);
254  break;
255 
256  case SHDR_TYLIST:
257  Tylist_Table.Transfer ((TYLIST *) addr, hdr.size / hdr.entsize);
258  break;
259 
260  case SHDR_TCON:
261  Tcon_Table.Transfer ((TCON *) addr, hdr.size / hdr.entsize);
262  break;
263 
264  case SHDR_STR:
265  Initialize_TCON_strtab (addr, hdr.size);
266  break;
267 
268  case SHDR_INITO:
270  Transfer ((INITO *) addr, hdr.size / hdr.entsize);
271  break;
272 
273  case SHDR_INITV:
274  Initv_Table.Transfer ((INITV *) addr, hdr.size / hdr.entsize);
275  break;
276 
277  case SHDR_BLK:
278  Blk_Table.Transfer ((BLK *) addr, hdr.size / hdr.entsize);
279  break;
280 
281  case SHDR_ST_ATTR:
283  Transfer ((ST_ATTR *) addr, hdr.size / hdr.entsize);
284  break;
285  }
286  }
287 
288  return 0;
289 } // WN_get_global_symtab
290 
291 
292 /* Given a handle returned by WN_open_input(), this function
293  * sets up the SCOPE structure.
294  * Returns -1 if error, 0 if success.
295  * Assume that global symtab and string table are already read.
296  */
297 
298 INT
299 WN_get_symtab (void *handle, PU_Info *pu)
300 {
302  if (st == Subsect_InMem)
303  return 0;
304  else if (st != Subsect_Exists)
305  return ERROR_RETURN;
306 
308  if (shdr.offset == 0)
309  return ERROR_RETURN;
310 
311  const char *base = (char *) handle + shdr.offset +
314  const LOCAL_SYMTAB_HEADER_TABLE *lsymtab =
315  (LOCAL_SYMTAB_HEADER_TABLE *) base;
316 
317  if (lsymtab->size < sizeof(lsymtab) ||
318  lsymtab->entries < LOCAL_SYMTAB_TABLES || lsymtab->size > size) {
319  errno = EINVAL;
320  return ERROR_RETURN;
321  }
322 
323  UINT i;
324  for (i = 0; i < LOCAL_SYMTAB_TABLES; ++i)
325  if (lsymtab->header[i].offset + lsymtab->header[i].size > size) {
326  errno = EINVAL;
327  return ERROR_RETURN;
328  }
329 
330  for (i = 0; i < LOCAL_SYMTAB_TABLES; ++i) {
331  const SYMTAB_HEADER& hdr = lsymtab->header[i];
332  const char *addr = base + hdr.offset;
333 
334  switch (hdr.type) {
335 
336  case SHDR_ST:
337  Is_True(Scope_tab[CURRENT_SYMTAB].st_tab != 0,
338  ("Null st_tab, level = %d", CURRENT_SYMTAB));
340  Transfer ((ST *) addr, hdr.size / hdr.entsize);
341  break;
342 
343  case SHDR_LABEL:
344  Is_True(Scope_tab[CURRENT_SYMTAB].label_tab != 0,
345  ("Null label_tab, level = %d", CURRENT_SYMTAB));
347  Transfer ((LABEL *) addr, hdr.size / hdr.entsize);
348  break;
349 
350  case SHDR_PREG:
351  Is_True(Scope_tab[CURRENT_SYMTAB].preg_tab != 0,
352  ("Null preg_tab, level = %d", CURRENT_SYMTAB));
354  Transfer ((PREG *) addr, hdr.size / hdr.entsize);
355  break;
356 
357  case SHDR_INITO:
358  Is_True(Scope_tab[CURRENT_SYMTAB].inito_tab != 0,
359  ("Null inito_tab, level = %d", CURRENT_SYMTAB));
361  Transfer ((INITO *) addr, hdr.size / hdr.entsize);
362  break;
363 
364  case SHDR_ST_ATTR:
365  Is_True(Scope_tab[CURRENT_SYMTAB].st_attr_tab != 0,
366  ("Null st_attr_tab, level = %d", CURRENT_SYMTAB));
368  Transfer ((ST_ATTR *) addr, hdr.size / hdr.entsize);
369  break;
370  }
371  }
372 
374 
375  return 0;
376 } /* WN_get_symtab */
377 
378 
379 INT
380 WN_get_strtab (void *handle)
381 {
383  if (shdr.offset == 0)
384  return ERROR_RETURN;
385 
386  Initialize_Strtab ((char *) handle + shdr.offset, shdr.size);
387 
388  return 0;
389 } // WN_get_strtab
390 
391 
392 /*
393  * Note: fix_tree is a hot spot for the binary reader, so be very careful
394  * to make everything as fast as possible.
395  */
396 
397 static INT
398 fix_tree (WN *node, char *base, Elf64_Word size)
399 {
400  OPCODE opcode = (OPCODE) WN_opcode (node);
401  WN *wn;
402 
403 #if defined(Is_True_On) || defined(DEBUG_IR)
404  if (verbose_info) {
405  printf("opcode %s\n", OPCODE_name(opcode));
406  last_node = node;
407  }
408 #endif
409 
410 #ifndef CFE
411  if (opcode == OPC_REGION)
413 #endif
414 
415 #if defined(BACK_END)
416  if (opcode == OPC_ALTENTRY)
418 
419  /* Count whirl nodes that are useful for Olimit and other stats */
421 #endif
422 
423  if (opcode == OPC_BLOCK) {
424  wn = WN_first(node);
425  if (wn == (WN *) -1) {
426  WN_first(node) = NULL;
427  WN_last(node) = NULL;
428  } else {
429  CONVERT_OFFSET(WN*, wn);
430  WN_first(node) = wn;
431  CONVERT_OFFSET(WN*, WN_last(node));
432 
433  do {
434  if (fix_tree (wn, base, size) == ERROR_VALUE)
435  return ERROR_VALUE;
436  wn = WN_next(wn);
437  } while (wn);
438  }
439  } else if (!OPCODE_is_leaf(opcode)) {
440  register INT i, cnt;
441  register WN **wn_ptr;
442 
443  cnt = WN_kid_count(node);
444  wn_ptr = &WN_kid(node, 0);
445  for (i = 0; i < cnt; i++, wn_ptr++) {
446  wn = *wn_ptr;
447  if (wn == (WN *) -1) {
448  *wn_ptr = NULL;
449  } else {
450  CONVERT_OFFSET(WN*, wn);
451  *wn_ptr = wn;
452  if (fix_tree (wn, base, size) == ERROR_VALUE)
453  return ERROR_VALUE;
454  }
455  }
456  }
457 
458  if (OPCODE_has_next_prev(opcode)) {
459  wn = WN_prev(node);
460  if (wn == (WN *) -1) {
461  WN_prev(node) = NULL;
462  } else {
463  CONVERT_OFFSET(WN*, wn);
464  WN_prev(node) = wn;
465  }
466  wn = WN_next(node);
467  if (wn == (WN *) -1) {
468  WN_next(node) = NULL;
469  } else {
470  CONVERT_OFFSET(WN*, wn);
471  WN_next(node) = wn;
472  }
473  }
474 
475  /* keep track of the last map ID in each opcode category */
476  if (WN_map_id(node) != -1) {
477  register OPERATOR_MAPCAT category = OPCODE_mapcat(opcode);
478  register INT32 map_id = WN_map_id(node);
479  register INT32 *last_id_ptr;
480 
481  last_id_ptr = &WN_MAP_TAB_Last_ID(Current_Map_Tab, category);
482  if (map_id > *last_id_ptr) {
483  *last_id_ptr = map_id;
484  }
485  }
486 
487  return 0;
488 } /* fix_tree */
489 
490 
491 
492 void
494 {
495  verbose_info = val;
496 }
497 
498 
499 template <class ELF>
500 INT
501 check_elf_header (const char* baseaddr, Elf64_Word size, const ELF& tag)
502 {
503  typename ELF::Elf_Ehdr* ehdr = (typename ELF::Elf_Ehdr*) baseaddr;
504  if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
505  ehdr->e_version != EV_CURRENT) {
506  return ERROR_RETURN;
507  }
508  if (ehdr->e_type != ET_IR
509  || ehdr->e_shentsize != sizeof(typename ELF::Elf_Shdr)) {
510  return ERROR_RETURN;
511  }
512  if (Target_ABI != ABI_UNDEF &&
513  // only check if expecting a certain target
514  ehdr->e_machine != Get_Elf_Target_Machine())
515  return ABI_MISMATCH;
516  BOOL is_64bit;
517  INT isa;
518  Config_Target_From_ELF (ehdr->e_flags, &is_64bit, &isa);
519  if ( ! Set_Target_ABI (is_64bit, isa))
520  return ABI_MISMATCH;
521  if (ehdr->e_shstrndx >= ehdr->e_shnum) {
522  return ERROR_RETURN;
523  }
524  if (ehdr->e_shoff >= size ||
525  ehdr->e_shoff + ehdr->e_shnum * sizeof(typename ELF::Elf_Shdr) > size) {
526  return ERROR_RETURN;
527  }
528  typename ELF::Elf_Shdr* shdr =
529  (typename ELF::Elf_Shdr *) (baseaddr + ehdr->e_shoff);
530  if ((long) shdr & (ALIGNOF(typename ELF::Elf_Shdr) - 1)) {
531  return ERROR_RETURN;
532  }
533  return tag.Elf_class();
534 }
535 
536 
537 static INT
538 check_elf_header (const char *baseaddr, Elf64_Word size)
539 {
540  if (size < sizeof(Elf64_Ehdr))
541  return ERROR_RETURN;
542  Elf64_Ehdr* ehdr = (Elf64_Ehdr *) baseaddr;
543  if (!IS_ELF (*ehdr))
544  return ERROR_RETURN;
545  if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) {
546  return check_elf_header (baseaddr, size, ELF64()); }
547 
548 #ifndef __ALWAYS_USE_64BIT_ELF__
549  else if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
550  return check_elf_header (baseaddr, size, ELF32());
551 #endif
552  else
553  return ERROR_RETURN;
554 } /* check_elf_header */
555 
556 
557 // Note: file_revision may be changed
558 template <class ELF>
559 INT
561  char* file_revision, const ELF& tag)
562 {
563  typename ELF::Elf_Ehdr* ehdr = (typename ELF::Elf_Ehdr*) baseaddr;
564  typename ELF::Elf_Shdr* shdr =
565  (typename ELF::Elf_Shdr*) (baseaddr + ehdr->e_shoff);
566 
567  errno = ENOEXEC;
568 
569  if (shdr[ehdr->e_shstrndx].sh_offset >= size ||
570  shdr[ehdr->e_shstrndx].sh_offset +
571  shdr[ehdr->e_shstrndx].sh_size > size)
572  return ERROR_RETURN;
573 
574  char* shstrtab = baseaddr + shdr[ehdr->e_shstrndx].sh_offset;
575 
576  for (INT i = 1; i < ehdr->e_shnum; i++) {
577  if (shdr[i].sh_offset >= size ||
578  shdr[i].sh_offset + shdr[i].sh_size > size)
579  return ERROR_RETURN;
580  if (shdr[i].sh_name >= shdr[ehdr->e_shstrndx].sh_size)
581  return ERROR_RETURN;
582  if (shdr[i].sh_link >= ehdr->e_shnum)
583  return ERROR_RETURN;
584  if (shdr[i].sh_addralign & (shdr[i].sh_addralign - 1))
585  return ERROR_RETURN;
586  if (shdr[i].sh_addralign > 1 &&
587  (long)(baseaddr + shdr[i].sh_offset) & ((shdr[i].sh_addralign - 1)))
588  return ERROR_RETURN;
589 
590  /* search for and verify the revision string */
591  if (shdr[i].sh_type == SHT_PROGBITS &&
592  strcmp (shstrtab + shdr[i].sh_name, ELF_COMMENT) == 0) {
593  register char *p = baseaddr + shdr[i].sh_offset;
594  register char *eob = p + shdr[i].sh_size - 1;
595  register int match = 0;
596 
597  if (*eob != 0)
598  /* section not NULL-terminated */
599  return ERROR_RETURN;
600 
601  while (p <= eob) {
602  if (strncmp ("WHIRL:", p, 6) == 0) {
603  strcpy (file_revision, p);
604  if (strcmp (WHIRL_REVISION, p) == 0) {
605  match = 1;
606  break;
607  }
608  }
609  p += strlen (p) + 1;
610  }
611 
612  if (!match && DEBUG_Ir_Version_Check)
613  return REVISION_MISMATCH;
614  }
615  }
616 
617  errno = 0;
618  return 1;
619 } /* check_section_headers */
620 
621 static INT
623 {
624  register char **argv;
625  register Elf64_Word argc;
626 
627  if (sizeof(Elf64_Word) > size)
628  return ERROR_RETURN;
629 
630  argc = *((Elf64_Word *) base);
631 
632  if (sizeof(Elf64_Word) + argc * sizeof(Elf64_Word) > size)
633  return ERROR_RETURN;
634  argv = (char **) (base + sizeof(Elf64_Word));
635 
636  while (argc--) {
637  register Elf64_Word offset = *((Elf64_Word *)argv);
638 
639  if (offset > size)
640  return ERROR_RETURN;
641  *argv = base + offset;
642  argv++;
643  }
644 
645  return 0;
646 } /* fix_comp_flags */
647 
648 
649 // Note: 'file_revision' may be changed
650 INT
652 {
653  INT st;
654 
655  if ((st = check_elf_header (baseaddr, size)) < 0)
656  return st;
657 
658 #ifndef __ALWAYS_USE_64BIT_ELF__
659  if (st == ELFCLASS32) {
660  if ((st = check_section_headers (baseaddr, size, file_revision,
661  ELF32())) <= 0)
662  return st;
663  } else
664 #endif
665  {
666  if ((st = check_section_headers (baseaddr, size, file_revision,
667  ELF64())) <= 0)
668  return st;
669  }
670 
671  return 1;
672 } /* WN_massage_input */
673 
674 
675 // Note: 'file_revision' may be changed
676 static void *
677 read_file (const char *filename, off_t* mapped_size, char* file_revision)
678 {
679  int fd;
680  INT st;
681  struct stat stat_buf;
682  register char *map_addr;
683 
684  fd = open (filename, O_RDONLY);
685  if (fd < 0)
686  return (void *) ERROR_RETURN;
687 
688  if (fstat (fd, &stat_buf) != 0)
689  return (void *) ERROR_RETURN;
690 
691  map_addr = (char *) mmap (0, stat_buf.st_size, PROT_READ|PROT_WRITE,
692  MAP_PRIVATE, fd, 0);
693  if (map_addr == (char *)(ERROR_VALUE)) {
694  close (fd);
695  return (void *) ERROR_RETURN;
696  }
697 
698  close (fd);
699 
700  if ((st = WN_massage_input(map_addr, stat_buf.st_size,
701  file_revision)) <= 0) {
702  munmap (map_addr, stat_buf.st_size);
703  return (void *) (st);
704  }
705 
706  /* if everything is fine, save the size of the file */
707  *mapped_size = stat_buf.st_size;
708  return map_addr;
709 
710 } /* read_file */
711 
712 
714 Get_Elf_Section_Size (void *handle, Elf64_Word type, Elf64_Word info)
715 {
716  OFFSET_AND_SIZE shdr = get_section (handle, type, info);
717  if (shdr.offset == 0) return 0;
718  return shdr.size;
719 }
720 
721 /*
722  * Specify the name of the WHIRL file for reading. If successful, a handle
723  * will be returned. If the binary was a different revision than what we
724  * expected, it returns (void*) REVISION_MISMATCH.
725  * Otherwise, it returns (void *) READER_ERROR and sets errno.
726  */
727 
728 void *
729 WN_open_input (const char *filename, off_t *mapped_size)
730 {
731  if (filename == 0) {
732  errno = ENOENT;
733  return (void *) ERROR_RETURN;
734  }
735 
736  errno = 0;
737 
738  return read_file (filename, mapped_size, file_revision);
739 
740 } /* WN_open_input */
741 
742 
743 /* open a new file, used by the inliner when performing across
744  * file inlining. Note, mapped file size is not saved in the
745  * static variable. Note that 'file_revision' may change.
746  */
747 extern void *
748 WN_inline_open_file(const char* file_name, off_t *mapped_size,
749  char* file_revision)
750 {
751  if (file_name == 0) {
752  errno = ENOENT;
753  return (void *) ERROR_RETURN;
754  }
755 
756  errno = 0;
757 
758  return read_file (file_name, mapped_size, file_revision);
759 
760 }
761 
762 
763 /*
764  * Read the PU headers. Returns a pointer to the root of the PU_Info
765  * tree or -1 on error. Returns the number of PUs through the p_num_PUs
766  * parameter.
767  */
768 
769 PU_Info *
770 WN_get_PU_Infos (void *handle, INT32 *p_num_PUs)
771 {
772  char *base;
773  INT32 size;
774  PU_Info *pu_tree;
775 
777  if (shdr.offset == 0) return (PU_Info *)ERROR_RETURN;
778 
779  base = (char *) handle + shdr.offset;
780  size = shdr.size;
781 
782  pu_tree = Read_PU_Infos (base, size, p_num_PUs);
783  if (pu_tree == (PU_Info *)ERROR_VALUE)
784  return (PU_Info *)ERROR_RETURN;
785 
786  return pu_tree;
787 }
788 
789 
790 #ifdef BACK_END
791 void *
792 WN_get_section_base (void *handle, INT sect)
793 {
794  char *base;
795 
796  OFFSET_AND_SIZE shdr = get_section (handle, SHT_MIPS_WHIRL, sect);
797  if (shdr.offset == 0) return (void *) ERROR_RETURN;
798 
799  base = (char *) handle + shdr.offset;
800  return (void *) base;
801 }
802 #endif
803 
804 
805 /*
806  * Convert the procedure ST in a PU_Info from an ID number to an
807  * ST pointer.
808  */
809 
810 ST *
812 {
814 
815  if (st == Subsect_InMem)
816  return &St_Table[PU_Info_proc_sym(pu)];
817  if (st != Subsect_Exists)
818  return (ST *) ERROR_RETURN;
819  ST *ps = &St_Table[PU_Info_proc_sym(pu)];
820  if (ps == NULL)
821  return (ST *) ERROR_RETURN;
822 
824 
825  return ps;
826 }
827 
828 
829 /*
830  * Given a handle returned by WN_open_input() and a PU_Info structure,
831  * this function reads the WHIRL tree for the PU. It returns (WN *)(-1)
832  * if there is an error.
833  */
834 
835 WN *
836 WN_get_tree (void *handle, PU_Info *pu)
837 {
838  register char *section_base, *tree_base;
839  register Elf64_Word offset, size;
840  WN *wn;
841  Elf64_Word first_node;
843 
844  if (st == Subsect_InMem)
845  return PU_Info_tree_ptr(pu);
846  if (st != Subsect_Exists)
847  return (WN *) ERROR_RETURN;
848 
849  offset = PU_Info_subsect_offset(pu, WT_TREE);
850  size = PU_Info_subsect_size(pu, WT_TREE);
851 
853  if (shdr.offset == 0) return (WN *) ERROR_RETURN;
854 
855  if (offset + size > shdr.size) {
856  errno = EINVAL;
857  return (WN *) ERROR_RETURN;
858  }
859 
860  section_base = (char *) handle + shdr.offset;
861  tree_base = section_base + offset;
862 
863  /* the offset of the first node is at the beginning of the subsection */
864  first_node = *(Elf64_Word *)tree_base;
865  wn = (WN *) (tree_base + first_node);
866 
867 #ifndef CFE
868  Set_Max_Region_Id(0); /* reset max id for pu */
869 #endif
870 
871  /* fix up the pointers in the WNs (Note: this must happen after the map
872  table is set up because it also updates the map ID info in the
873  map table */
874 
876  if (fix_tree (wn, tree_base, size) == ERROR_VALUE)
877  return (WN *)ERROR_VALUE;
878 
879  WN_next(wn) = NULL;
880  WN_prev(wn) = NULL;
881 
882  Set_PU_Info_tree_ptr(pu, wn);
884 
885  return wn;
886 } /* WN_get_tree */
887 
888 
889 /*
890  * Given a handle returned by WN_open_input(), this functions returns the
891  * argc and argv pairs for the command line for compiling the IR. The
892  * value of argc is returned as function return value and is set to 0 if
893  * the command line cannot be found (or if it is corrupted). The argv is
894  * passed as a referenced paramenter as the second argument.
895  */
896 
897 INT
898 WN_get_flags (void *handle, char ***argv)
899 {
900  Elf64_Word argc;
901  char *baseaddr;
902 
904  if (shdr.offset == 0) return 0;
905 
906  baseaddr = (char *) handle + shdr.offset;
907  if (fix_comp_flags (baseaddr, shdr.size) == ERROR_VALUE)
908  return 0;
909  argc = *((Elf64_Word *) baseaddr);
910  *argv = (char **) (baseaddr + sizeof(Elf64_Word));
911 
912  return argc;
913 } /* WN_get_flags */
914 
915 
916 /*
917  * Given a handle returned by WN_open_input(), this function
918  * initializes the debug symbol table (dst) with the data in the file.
919  * Returns -1 if fails, else the size of the section.
920  */
921 
922 INT
923 WN_get_dst (void *handle)
924 {
925  register INT size, num_blocks;
926  char *base, *ptr, *blk;
927  DST_BLOCK_IDX j;
928 
930  if (shdr.offset == 0) return ERROR_RETURN;
931 
932  base = (char *) handle + shdr.offset;
933  size = shdr.size;
934 
935  /* sections contains data, then array of block_headers, then num_blocks. */
936  ptr = base + size - sizeof(mINT32);
937  num_blocks = *(INT32*) ptr;
938  num_blocks++; /* last_block_number + 1 == number of blocks */
939  ptr -= (num_blocks * sizeof(block_header));
940 
941  DST_Init (ptr, num_blocks);
942  FOREACH_DST_BLOCK(j) {
943  blk = ((DST_Type *)Current_DST)->dst_blocks[j].offset;
944  if (blk == (char *)-1) {
945  ((DST_Type *)Current_DST)->dst_blocks[j].offset = NULL;
946  } else {
947  CONVERT_OFFSET(char*, blk);
948  ((DST_Type *)Current_DST)->dst_blocks[j].offset = blk;
949  }
950  }
951 
952  return size;
953 } /* WN_get_dst */
954 
955 
956 #if defined(BACK_END) || defined(IR_TOOLS)
957 // read the feedback info, if any
958 INT
959 WN_get_feedback (void* handle, PU_Info* pu, MEM_POOL* pool)
960 {
962 
963  switch (st) {
964  case Subsect_Missing:
965  case Subsect_InMem:
966  default:
967  return 0;
968  case Subsect_Exists:
969  break;
970  case Subsect_Written:
971  return ERROR_RETURN;
972  }
973 
977  if (shdr.offset == 0)
978  return ERROR_RETURN;
979 
980  if (offset + size >= shdr.size) {
981  errno = EINVAL;
982  return ERROR_RETURN;
983  }
984 
985  INTPTR baseaddr = (INTPTR)handle + shdr.offset + offset;
986 
987  Set_PU_Info_feedback_ptr (pu, baseaddr);
989 
990  return 0;
991 } // WN_get_feedback
992 #endif
993 
994 
995 
996 #if defined(BACK_END) || defined(BUILD_WNPREFETCH)
997 /* Read the prefetch pointer mapping */
998 INT
999 WN_get_prefetch (void *handle, PU_Info *pu)
1000 {
1001  Elf64_Word offset, size;
1002  char *cur_addr, *end_addr, *tree_base;
1003  Elf64_Word node_offset;
1004  WN *node;
1005  PF_POINTER *pf_ptr;
1008 
1009  if (st == Subsect_Written)
1010  return ERROR_RETURN;
1011  if (st != Subsect_Exists)
1012  return 0;
1013 
1014  offset = PU_Info_subsect_offset(pu, WT_PREFETCH);
1015  size = PU_Info_subsect_size(pu, WT_PREFETCH);
1016 
1018  if (shdr.offset == 0) return ERROR_RETURN;
1019 
1020  if (offset + size >= shdr.size) {
1021  errno = EINVAL;
1022  return ERROR_RETURN;
1023  }
1024 
1025  /* find the start of the tree subsection */
1026  tree_base = (char *) handle + shdr.offset +
1028 
1029  cur_addr = (char *)handle + shdr.offset + offset;
1030  end_addr = cur_addr + size;
1031 
1032  for (;;) {
1033  node_offset = *(Elf64_Word *)cur_addr;
1034  cur_addr += (sizeof(Elf64_Word));
1035 
1036  if (node_offset == (Elf64_Word)-1) break;
1037 
1038  cur_addr = (char *)ir_b_align((off_t)cur_addr, ALIGNOF(PF_POINTER),
1039  0);
1040  pf_ptr = (PF_POINTER *)cur_addr;
1041  cur_addr += (sizeof(PF_POINTER));
1042 
1043  /* fixup the WN pointers. If -1 then store NULL */
1044  node = (WN *)(tree_base + node_offset);
1045  if (pf_ptr->wn_pref_1L == (WN*) -1) {
1046  pf_ptr->wn_pref_1L = NULL;
1047  } else {
1048  pf_ptr->wn_pref_1L =
1049  (WN*)(tree_base + (INTPTR)pf_ptr->wn_pref_1L);
1050  }
1051 
1052  if (pf_ptr->wn_pref_2L == (WN*) -1) {
1053  pf_ptr->wn_pref_2L = NULL;
1054  } else {
1055  pf_ptr->wn_pref_2L =
1056  (WN*)(tree_base + (INTPTR)pf_ptr->wn_pref_2L);
1057  }
1058 
1059  /* add the pointer to the prefetch mapping */
1060  WN_MAP_Set(WN_MAP_PREFETCH, node, (void *)pf_ptr);
1061 
1062  if (cur_addr > end_addr) return ERROR_RETURN;
1063  }
1064 
1067 
1068  return 0;
1069 } /* WN_get_prefetch */
1070 
1071 #endif /* BACK_END || BUILD_WNPREFETCH */
1072 
1073 static inline void
1074 WN_MAP_put(WN_MAP wn_map, WN *wn, INT32 value)
1075 {
1076  WN_MAP32_Set(wn_map, wn, value);
1077 }
1078 
1079 static inline void
1080 WN_MAP_put(WN_MAP wn_map, WN *wn, INT64 value)
1081 {
1082  WN_MAP64_Set(wn_map, wn, value);
1083 }
1084 
1085 static inline void
1086 WN_MAP_put(WN_MAP wn_map, WN *wn, void *value)
1087 {
1088  WN_MAP_Set(wn_map, wn, value);
1089 }
1090 
1091 template<class MAP_ENTRY_TYPE>
1092 static inline INT
1093 WN_read_generic_map(void *handle,
1094  PU_Info *pu,
1095  INT32 subsection_type,
1096  WN_MAP value_map,
1097  MAP_ENTRY_TYPE)
1098 {
1099  Subsect_State state = PU_Info_state (pu, subsection_type);
1100  Elf64_Word offset, size;
1101  char *cur_addr, *end_addr, *tree_base;
1102 
1103  if (state == Subsect_Written) {
1104  return ERROR_RETURN;
1105  }
1106  if (state != Subsect_Exists) {
1107  return 0;
1108  }
1109 
1111  if (shdr.offset == 0) {
1112  return ERROR_RETURN;
1113  }
1114 
1115  offset = PU_Info_subsect_offset(pu, subsection_type);
1116  size = PU_Info_subsect_size(pu, subsection_type);
1117 
1118  if (offset + size >= shdr.size) {
1119  errno = EINVAL;
1120  return ERROR_RETURN;
1121  }
1122 
1123  /* find the start of the tree subsection */
1124  tree_base = (char *) handle + shdr.offset +
1126 
1127  cur_addr = (char *)handle + shdr.offset + offset;
1128  end_addr = cur_addr + size;
1129 
1130  for (;;) {
1131  MAP_ENTRY_TYPE map_value;
1132  Elf64_Word node_offset = *(Elf64_Word *) cur_addr;
1133  WN *node;
1134 
1135  cur_addr += (sizeof(Elf64_Word)); // advance over WN offset
1136 
1137  if (node_offset == (Elf64_Word)-1)
1138  break;
1139 
1140  // Why do we align here but not for the WN offset? -- RK 980615
1141  cur_addr = (char *) ir_b_align ((off_t) cur_addr,
1142  sizeof(MAP_ENTRY_TYPE),
1143  0);
1144  map_value = * (MAP_ENTRY_TYPE *) cur_addr;
1145  cur_addr += sizeof(MAP_ENTRY_TYPE); // advance over map entry
1146 
1147  node = (WN *) (tree_base + node_offset);
1148 
1149  // TODO: The following must be made generic.
1150  /* add the value to the WHIRL map in memory */
1151  WN_MAP_put(value_map, node, map_value);
1152 
1153  if (cur_addr > end_addr)
1154  return ERROR_RETURN;
1155  }
1156 
1157  PU_Info_subsect_ptr(pu, subsection_type) = NULL;
1158  Set_PU_Info_state(pu, subsection_type, Subsect_InMem);
1159 
1160  return 0;
1161 }
1162 
1163 INT
1164 WN_get_INT32_map(void *handle,
1165  PU_Info *pu,
1166  INT32 subsection_type,
1167  WN_MAP value_map)
1168 {
1169  return WN_read_generic_map(handle, pu, subsection_type,
1170  value_map, (INT32) 0);
1171 }
1172 
1173 INT
1174 WN_get_voidptr_map(void *handle,
1175  PU_Info *pu,
1176  INT32 subsection_type,
1177  WN_MAP value_map)
1178 {
1179  return WN_read_generic_map(handle, pu, subsection_type,
1180  value_map, (void *) 0);
1181 }
1182 
1183 
1184 
1185 /*
1186  * Given a handle returned by WN_open_input(), this function releases all
1187  * the memory used for reading the WHIRL file. Note that previously
1188  * pointers returned by WN_get_tree() will no longer be valid.
1189  */
1190 
1191 void
1192 WN_free_input (void *handle, off_t mapped_size)
1193 {
1194  if (handle == 0 || handle == (void *)(-1))
1195  return;
1196 
1197  // Solaris CC, against UNIX standard, wants first arg to be char*.
1198  munmap ((char*)handle, mapped_size);
1199 } /* WN_free_input */
1200 
1201 
1202 #ifndef OWN_ERROR_PACKAGE
1203 /*
1204  * Define common routines for reading all the whirl sections.
1205  * These routines use the standard compiler error reporting mechanism.
1206  */
1207 
1208 static void *global_fhandle; /* file handle */
1209 static void *local_fhandle; /* file handle */
1210 static const char *global_ir_file; /* name of ir input file */
1211 static const char *local_ir_file; /* name of ir input file */
1212 
1213 static void
1214 open_specified_input (const char *input_file, const char **ir_input,
1215  void **fhandle, off_t *mapped_size)
1216 {
1217  Set_Error_Phase ( "Reading WHIRL file" );
1218  *ir_input = input_file;
1219  *fhandle = WN_open_input (input_file, mapped_size);
1220 
1221  if (*fhandle == (void*) REVISION_MISMATCH) {
1222  ErrMsg ( EC_IR_Revision, file_revision, *ir_input);
1223  } else if (*fhandle == (void*) ABI_MISMATCH) {
1225  "abi of whirl file doesn't match abi from command-line",
1226  *ir_input);
1227  } else if (*fhandle == (void*) READER_ERROR) {
1228  ErrMsg ( EC_IR_Open, *ir_input, errno );
1229  }
1230 }
1231 
1232 // same ir file for both global and local
1233 void *
1235 {
1236  open_specified_input (input_file,
1241  return global_fhandle;
1242 }
1243 
1244 void *
1246 {
1247  open_specified_input (input_file,
1249  return global_fhandle;
1250 }
1251 
1252 void *
1254 {
1255  open_specified_input (input_file,
1257  return local_fhandle;
1258 }
1259 
1260 /*
1261  * Read all the global tables and the PU section header. Returns a
1262  * pointer to the PU_Info tree. If "p_num_PUs" is non-NULL, the number
1263  * of PUs is returned through it.
1264  */
1265 
1266 PU_Info *
1268 {
1269  PU_Info *pu_tree;
1270 
1271  Set_Error_Phase ( "Reading WHIRL file" );
1272 
1273  if (WN_get_strtab(global_fhandle) == -1) {
1274  ErrMsg ( EC_IR_Scn_Read, "strtab", global_ir_file);
1275  }
1276 
1277  if ((INT) WN_get_global_symtab (global_fhandle) == -1) {
1278  ErrMsg ( EC_IR_Scn_Read, "global symtab", global_ir_file);
1279  }
1280 
1281 
1282  // for now, get dst from local file (later change to global)
1283  if (WN_get_dst(local_fhandle) == -1) {
1284  ErrMsg ( EC_IR_Scn_Read, "dst", local_ir_file);
1285  }
1286 
1287  // PU_Info is stored in local file
1288  pu_tree = WN_get_PU_Infos (local_fhandle, p_num_PUs);
1289  if (pu_tree == (PU_Info *)-1) {
1290  ErrMsg ( EC_IR_Scn_Read, "PU headers", local_ir_file);
1291  }
1292  if (verbose_info) {
1293  printf("done reading global info\n");
1294  }
1295 
1296  return pu_tree;
1297 }
1298 
1299 
1300 void
1302 {
1303  const char *save_phase = Get_Error_Phase();
1304  Set_Error_Phase ( "Reading WHIRL file" );
1305 
1306  /* set the map table */
1308  if (!Current_Map_Tab) {
1311  }
1312 
1315 
1316  if (WN_get_symtab (local_fhandle, pu) == -1)
1317  ErrMsg ( EC_IR_Scn_Read, "local symtab", local_ir_file);
1318 
1320  if (Scope_tab[CURRENT_SYMTAB].st == (ST *) -1)
1321  ErrMsg ( EC_IR_Scn_Read, "proc ST", local_ir_file);
1322  else
1324 
1325 
1326  if (WN_get_tree (local_fhandle, pu) == (WN*) -1) {
1327  ErrMsg ( EC_IR_Scn_Read, "tree", local_ir_file);
1328  }
1329 
1330 #if defined(BACK_END) || defined(BUILD_WNPREFETCH)
1331  if (WN_get_prefetch (local_fhandle, pu) == -1) {
1332  ErrMsg ( EC_IR_Scn_Read, "prefetch map", local_ir_file);
1333  }
1334 #endif
1335 
1336 
1339  ErrMsg ( EC_IR_Scn_Read, "alias class map", local_ir_file);
1340  }
1341 
1344  ErrMsg ( EC_IR_Scn_Read, "alias class internal map", local_ir_file);
1345  }
1346 
1347  Set_Error_Phase(save_phase);
1348 }
1349 
1350 
1351 void
1353 {
1355 
1356  /* deallocate the old map table */
1357  if (PU_Info_maptab(pu)) {
1359  PU_Info_maptab(pu) = NULL;
1360  }
1361 }
1362 
1363 void
1365 {
1367  local_fhandle = 0;
1368 }
1369 
1370 void
1372 {
1374  if (global_fhandle != local_fhandle) {
1375  Free_Local_Input();
1376  }
1377  global_fhandle = 0;
1378 }
1379 
1380 #endif /* OWN_ERROR_PACKAGE */
1381