OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / gcc / collect2.c
1 /* Collect static initialization info into data structures
2    that can be traversed by C++ initialization and finalization
3    routines.
4
5    Copyright (C) 1992 Free Software Foundation, Inc.
6    Contributed by Chris Smith (csmith@convex.com).
7    Heavily modified by Michael Meissner (meissner@osf.org),
8    Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
9
10 This file is part of GNU CC.
11
12 GNU CC is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2, or (at your option)
15 any later version.
16
17 GNU CC is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with GNU CC; see the file COPYING.  If not, write to
24 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
25
26
27 /* Build tables of static constructors and destructors and run ld. */
28
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include "gstddef.h"
35 #include <errno.h>
36 #include <signal.h>
37 #include <sys/file.h>
38 #include <sys/stat.h>
39 #include <sys/wait.h>
40
41 #define COLLECT
42
43 #include "config.h"
44
45 #ifndef __STDC__
46 #include "gvarargs.h"
47 #define generic char
48 #define PROTO(x) ()
49 #define const
50
51 #else
52 #include "stdarg.h"
53 #define generic void
54 #define PROTO(x) x
55 #endif
56
57 #ifdef OBJECT_FORMAT_ROSE
58
59 #ifdef _OSF_SOURCE
60 #define USE_MMAP
61 #endif
62
63 #ifdef USE_MMAP
64 #include <sys/mman.h>
65 #endif
66
67 #include <unistd.h>
68 #include <mach_o_format.h>
69 #include <mach_o_header.h>
70 #include <mach_o_vals.h>
71 #include <mach_o_types.h>
72 #endif /* OBJECT_FORMAT_ROSE */
73
74 /* Default flags to pass to nm.  */
75 #ifndef NM_FLAGS
76 #define NM_FLAGS "-p"
77 #endif
78
79 #ifdef USG
80 #define vfork fork
81 #endif
82
83 /* On MSDOS, write temp files in current dir
84    because there's no place else we can expect to use.  */
85 #if __MSDOS__
86 #ifndef P_tmpdir
87 #define P_tmpdir "./"
88 #endif
89 #endif
90
91 \f
92 /* Linked lists of constructor and destructor names. */
93
94 struct id 
95 {
96   struct id *next;
97   int sequence;
98   char name[1];
99 };
100
101 struct head
102 {
103   struct id *first;
104   struct id *last;
105   int number;
106 };
107
108 /* Enumeration giving which pass this is for scanning the program file.  */
109
110 enum pass {
111   PASS_FIRST,                           /* without constructors */
112   PASS_SECOND                           /* with constructors linked in */
113 };
114
115 extern char *sys_siglist[];
116 extern char *version_string;
117
118 static int vflag;                       /* true if -v */
119 static int rflag;                       /* true if -r */
120
121 static int debug;                       /* true if -debug */
122
123 static int   temp_filename_length;      /* Length of temp_filename */
124 static char *temp_filename;             /* Base of temp filenames */
125 static char *c_file;                    /* <xxx>.c for constructor/destructor list. */
126 static char *o_file;                    /* <xxx>.o for constructor/destructor list. */
127 static char *nm_file_name;              /* pathname of nm */
128
129 static struct head constructors;        /* list of constructors found */
130 static struct head destructors;         /* list of destructors found */
131
132 extern char *getenv             PROTO(( const char * ));
133 extern char *mktemp             PROTO(( char * ));
134 extern int   vfork              PROTO(( void ));
135 static void  add_to_list        PROTO(( struct head *headp, char *name ));
136 static void  scan_prog_file     PROTO(( char *, enum pass ));
137 static void  fork_execute       PROTO(( char *, char **argv ));
138 static void  do_wait            PROTO(( char * ));
139 static void  write_c_file       PROTO(( FILE *, char * ));
140 static void  my_exit            PROTO(( int ));
141 static void  handler            PROTO(( int ));
142 static void  maybe_unlink       PROTO(( char * ));
143 static void  choose_temp_base   PROTO(( void ));
144
145 generic         *xcalloc        PROTO(( size_t, size_t ));
146 generic         *xmalloc        PROTO(( size_t ));
147
148 \f
149
150 #if !defined(HAVE_STRERROR) && !defined(_OSF_SOURCE)
151
152 char *strerror (e)
153      int e;
154 {
155   extern char *sys_errlist[];
156   extern int sys_nerr;
157   static char buffer[30];
158
159   if (!e)
160     return "";
161
162   if (e > 0 && e < sys_nerr)
163     return sys_errlist[e];
164
165   sprintf (buffer, "Unknown error %d", e);
166   return buffer;
167 }
168
169 #endif
170
171 \f
172 /* Delete tempfiles and exit function.  */
173
174 static void
175 my_exit (status)
176      int status;
177 {
178   if (c_file[0])
179     maybe_unlink (c_file);
180
181   if (o_file[0])
182     maybe_unlink (o_file);
183
184   exit (status);
185 }
186
187 \f
188 #ifndef __STDC__
189
190 /* Die when sys call fails. */
191
192 /*VARARGS*/
193 static void
194 fatal_perror (va_alist)
195 {
196   char *string;
197   va_list vptr;
198   int e = errno;
199
200   va_start (vptr);
201   string = va_arg (vptr, char *);
202   fprintf (stderr, "collect: ");
203   vfprintf (stderr, string, vptr);
204   fprintf (stderr, ": %s\n", strerror (e));
205   va_end (vptr);
206   my_exit (1);
207 }
208
209 /* Just die. */
210
211 /*VARARGS*/
212 static void
213 fatal (va_alist)
214 {
215   char *string;
216   va_list vptr;
217
218   va_start (vptr);
219   string = va_arg (vptr, char *);
220   fprintf (stderr, "collect: ");
221   vfprintf (stderr, string, vptr);
222   fprintf (stderr, "\n");
223   va_end (vptr);
224   my_exit (1);
225 }
226
227 /* Write error message.  */
228
229 /*VARARGS*/
230 static void
231 error (va_alist)
232 {
233   char *string;
234   va_list vptr;
235
236   va_start (vptr);
237   string = va_arg (vptr, char *);
238   fprintf (stderr, "collect: ");
239   vfprintf (stderr, string, vptr);
240   fprintf (stderr, "\n");
241   va_end (vptr);
242 }
243
244 #else
245
246 static void
247 fatal_perror (char *string, ...)
248 {
249   va_list vptr;
250   int e = errno;
251
252   va_start (vptr, string);
253   fprintf (stderr, "collect: ");
254   vfprintf (stderr, string, vptr);
255   fprintf (stderr, ": %s\n", strerror (e));
256   va_end (vptr);
257   my_exit (1);
258 }
259
260 /* Just die. */
261
262 static void
263 fatal (char *string, ...)
264 {
265   va_list vptr;
266
267   va_start (vptr, string);
268   fprintf (stderr, "collect: ");
269   vfprintf (stderr, string, vptr);
270   fprintf (stderr, "\n");
271   va_end (vptr);
272   my_exit (1);
273 }
274
275 /* Write error message.  */
276
277 static void
278 error (char *string, ...)
279 {
280   va_list vptr;
281
282   va_start (vptr, string);
283   fprintf (stderr, "collect: ");
284   vfprintf (stderr, string, vptr);
285   fprintf (stderr, "\n");
286   va_end (vptr);
287 }
288 #endif
289
290 \f
291 /* In case obstack is linked in, and abort is defined to fancy_abort,
292    provide a default entry.  */
293
294 void
295 fancy_abort ()
296 {
297   fatal ("internal error");
298 }
299
300 \f
301 static void
302 handler (signo)
303      int signo;
304 {
305   if (c_file[0])
306     maybe_unlink (c_file);
307
308   if (o_file[0])
309     maybe_unlink (o_file);
310
311   signal (signo, SIG_DFL);
312
313   fatal ("Caught signal %d [%s]", signo, sys_siglist[signo]);
314   kill (getpid (), signo);
315 }
316
317 \f
318 generic *
319 xcalloc (size1, size2)
320      size_t size1, size2;
321 {
322   generic *ptr = calloc (size1, size2);
323   if (ptr)
324     return ptr;
325
326   fatal ("Out of memory.");
327   return (generic *)0;
328 }
329
330 generic *
331 xmalloc (size)
332      size_t size;
333 {
334   generic *ptr = malloc (size);
335   if (ptr)
336     return ptr;
337
338   fatal ("Out of memory.");
339   return (generic *)0;
340 }
341
342 \f
343 /* Compute a string to use as the base of all temporary file names.
344    It is substituted for %g.  */
345
346 static void
347 choose_temp_base PROTO((void))
348 {
349   char *base = getenv ("TMPDIR");
350   int len;
351
352   if (base == (char *)0)
353     {
354 #ifdef P_tmpdir
355       if (access (P_tmpdir, R_OK | W_OK) == 0)
356         base = P_tmpdir;
357 #endif
358       if (base == (char *)0)
359         {
360           if (access ("/usr/tmp", R_OK | W_OK) == 0)
361             base = "/usr/tmp/";
362           else
363             base = "/tmp/";
364         }
365     }
366
367   len = strlen (base);
368   temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
369   strcpy (temp_filename, base);
370   if (len > 0 && temp_filename[len-1] != '/')
371     temp_filename[len++] = '/';
372   strcpy (temp_filename + len, "ccXXXXXX");
373
374   mktemp (temp_filename);
375   temp_filename_length = strlen (temp_filename);
376 }
377
378 \f
379 /* Main program. */
380
381 int
382 main (argc, argv)
383      int argc;
384      char *argv[];
385 {
386   char *outfile         = "a.out";
387   char *arg;
388   FILE *outf;
389   char *ld_file_name;
390   char *c_file_name;
391   char *B_option;
392   char *p;
393   char *prefix;
394   char **c_argv         = (char **) xcalloc (sizeof (char *), argc+7);
395   char **c_ptr          = c_argv;
396   char **ld1_argv       = (char **) xcalloc (sizeof (char *), argc+2);
397   char **ld1            = ld1_argv;
398   char **ld2_argv       = (char **) xcalloc (sizeof (char *), argc+5);
399   char **ld2            = ld2_argv;
400   int first_file;
401   int len;
402   int clen;
403
404 #ifdef DEBUG
405   debug = 1;
406   vflag = 1;
407 #endif
408
409   if (argc < 2)
410     fatal ("no arguments");
411
412   signal (SIGQUIT, handler);
413   signal (SIGINT,  handler);
414   signal (SIGALRM, handler);
415   signal (SIGHUP,  handler);
416   signal (SIGSEGV, handler);
417   signal (SIGBUS,  handler);
418
419   /* Try to discover a valid linker/assembler/nm to use.  */
420   len = strlen (argv[0]);
421   prefix = (char *)0;
422   if (len >= sizeof ("ld")-1)
423     {
424       p = argv[0] + len - sizeof ("ld") + 1;
425       if (strcmp (p, "ld") == 0)
426         {
427           prefix = argv[0];
428           *p = '\0';
429         }
430     }
431
432   if (prefix == (char *)0)
433     {
434       p = strrchr (argv[0], '/');
435       if (p != (char *)0)
436         {
437           prefix = argv[0];
438           p[1] = '\0';
439         }
440
441 #ifdef STANDARD_EXEC_PREFIX
442       else if (access (STANDARD_EXEC_PREFIX, X_OK) == 0)
443         prefix = STANDARD_EXEC_PREFIX;
444 #endif
445
446 #ifdef MD_EXEC_PREFIX
447       else if (access (MD_EXEC_PREFIX, X_OK) == 0)
448         prefix = MD_EXEC_PREFIX;
449 #endif
450
451       else if (access ("/usr/ccs/gcc", X_OK) == 0)
452         prefix = "/usr/ccs/gcc/";
453
454       else if (access ("/usr/ccs/bin", X_OK) == 0)
455         prefix = "/usr/ccs/bin/";
456
457       else
458         prefix = "/bin/";
459     }
460
461   clen = len = strlen (prefix);
462
463 #ifdef STANDARD_BIN_PREFIX
464   if (clen < sizeof (STANDARD_BIN_PREFIX) - 1)
465     clen = sizeof (STANDARD_BIN_PREFIX) - 1;
466 #endif
467
468   ld_file_name = xcalloc (len + sizeof ("real-ld"), 1);
469   c_file_name  = xcalloc (clen + sizeof ("gcc"), 1);
470   nm_file_name = xcalloc (len + sizeof ("gnm"), 1);
471   B_option     = xcalloc (len + sizeof ("-B"), 1);
472
473   memcpy (ld_file_name, prefix, len);
474   strcpy (ld_file_name + len, "real-ld");
475   if (access (ld_file_name, X_OK) < 0)
476     {
477       strcpy (ld_file_name + len, "gld");
478       if (access (ld_file_name, X_OK) < 0)
479         {
480           free (ld_file_name);
481 #ifdef REAL_LD_FILE_NAME
482           ld_file_name = REAL_LD_FILE_NAME;
483 #else
484           ld_file_name = (access ("/usr/bin/ld", X_OK) == 0) ? "/usr/bin/ld" : "/bin/ld";
485 #endif
486         }
487     }
488
489   memcpy (c_file_name, prefix, len);
490   strcpy (c_file_name + len, "gcc");
491   if (access (c_file_name, X_OK) < 0)
492     {
493 #ifdef STANDARD_BIN_PREFIX
494       strcpy (c_file_name, STANDARD_BIN_PREFIX);
495       strcat (c_file_name, "gcc");
496       if (access (c_file_name, X_OK) < 0)
497 #endif
498         {
499 #ifdef STANDARD_EXEC_PREFIX
500           strcpy (c_file_name, STANDARD_EXEC_PREFIX);
501           strcat (c_file_name, "gcc");
502           if (access (c_file_name, X_OK) < 0)
503 #endif
504             {
505               strcpy (c_file_name, "gcc");
506             }
507         }
508     }
509
510   memcpy (nm_file_name, prefix, len);
511   strcpy (nm_file_name + len, "nm");
512   if (access (nm_file_name, X_OK) < 0)
513     {
514       strcpy (nm_file_name + len, "gnm");
515       if (access (nm_file_name, X_OK) < 0)
516         {
517           free (nm_file_name);
518 #ifdef REAL_NM_FILE_NAME
519           nm_file_name = REAL_NM_FILE_NAME;
520 #else
521           nm_file_name = (access ("/usr/bin/nm", X_OK) == 0) ? "/usr/bin/nm" : "/bin/nm";
522 #endif
523         }
524     }
525
526   strcpy (B_option, "-B");
527   strcpy (B_option + sizeof ("-B") - 1, prefix);
528
529   *ld1++ = *ld2++ = "ld";
530
531   /* Make temp file names. */
532   choose_temp_base ();
533   c_file = xcalloc (temp_filename_length + sizeof (".c"), 1);
534   o_file = xcalloc (temp_filename_length + sizeof (".o"), 1);
535   sprintf (c_file, "%s.c", temp_filename);
536   sprintf (o_file, "%s.o", temp_filename);
537   *c_ptr++ = "gcc";
538   *c_ptr++ = "-c";
539   *c_ptr++ = "-o";
540   *c_ptr++ = o_file;
541
542   /* Parse arguments.  Remember output file spec, pass the rest to ld. */
543   /* After the first file, put in the c++ rt0 */
544   first_file = 1;
545   while ((arg = *++argv) != (char *)0)
546     {
547       *ld1++ = *ld2++ = arg;
548
549       if (arg[0] == '-')
550           switch (arg[1])
551             {
552             case 'd':
553               if (!strcmp (arg, "-debug"))
554                 {
555                   debug = 1;
556                   vflag = 1;
557                   ld1--;
558                   ld2--;
559                 }
560               break;
561
562               /* pass -f<xxx>, -B<xxx>, -b<xxx>, -V<xxx>, and -m<xxx>
563                  options to gcc.  This allows options to be passed
564                  that affect search rules, and the size of pointers. */
565             case 'b':
566             case 'B':
567             case 'f':
568             case 'm':
569             case 'V':
570               if (arg[1] != '\0')
571                 {
572                   ld1--;
573                   ld2--;
574                   *c_ptr++ = arg;
575                 }
576               break;
577
578             case 'o':
579               outfile = (arg[2] == '\0') ? argv[1] : &arg[2];
580               break;
581
582             case 'r':
583               if (arg[2] == '\0')
584                 rflag = 1;
585               break;
586
587             case 'v':
588               if (arg[2] == '\0')
589                 vflag = 1;
590               break;
591             }
592
593       else if (first_file
594                && (p = strrchr (arg, '.')) != (char *)0
595                && strcmp (p, ".o") == 0)
596         {
597           first_file = 0;
598           *ld2++ = o_file;
599         }
600     }
601
602   *c_ptr++ = B_option;
603   *c_ptr++ = c_file;
604   *c_ptr = *ld1 = *ld2 = (char *)0;
605
606   if (vflag)
607     {
608       fprintf (stderr, "GNU COLLECT2 version %s", version_string);
609 #ifdef TARGET_VERSION
610       TARGET_VERSION;
611 #endif
612       fprintf (stderr, "\n");
613     }
614
615   if (debug)
616     {
617       fprintf (stderr, "prefix       = %s\n", prefix);
618       fprintf (stderr, "ld_file_name = %s\n", ld_file_name);
619       fprintf (stderr, "c_file_name  = %s\n", c_file_name);
620       fprintf (stderr, "nm_file_name = %s\n", nm_file_name);
621       fprintf (stderr, "B_option     = %s\n", B_option);
622       fprintf (stderr, "c_file       = %s\n", c_file);
623       fprintf (stderr, "o_file       = %s\n", o_file);
624     }
625
626   /* Load the program, searching all libraries.
627      Examine the namelist with nm and search it for static constructors
628      and destructors to call.
629      Write the constructor and destructor tables to a .s file and reload. */
630
631   fork_execute (ld_file_name, ld1_argv);
632
633   /* If -r, don't build the constructor or destructor list, just return now.  */
634   if (rflag)
635     return 0;
636
637   scan_prog_file (outfile, PASS_FIRST);
638
639   if (debug)
640     {
641       fprintf (stderr, "%d constructor(s) found\n", constructors.number);
642       fprintf (stderr, "%d destructor(s)  found\n", destructors.number);
643     }
644
645   if (constructors.number == 0 && destructors.number == 0)
646     return 0;
647
648   outf = fopen (c_file, "w");
649   if (outf == (FILE *)0)
650     fatal_perror ("Can't write %s", c_file);
651
652   write_c_file (outf, c_file);
653
654   if (fclose (outf))
655     fatal_perror ("Can't close %s", c_file);
656
657   if (debug)
658     {
659       fprintf (stderr, "\n========== outfile = %s, c_file = %s\n", outfile, c_file);
660       write_c_file (stderr, "stderr");
661       fprintf (stderr, "========== end of c_file\n\n");
662     }
663
664   /* Assemble the constructor and destructor tables.
665      Link the tables in with the rest of the program. */
666
667   fork_execute (c_file_name,  c_argv);
668   fork_execute (ld_file_name, ld2_argv);
669
670   /* Let scan_prog_file do any final mods (OSF/rose needs this for
671      constructors/destructors in shared libraries.  */
672   scan_prog_file (outfile, PASS_SECOND);
673
674   maybe_unlink (c_file);
675   maybe_unlink (o_file);
676   return 0;
677 }
678
679 \f
680 /* Wait for a process to finish, and exit if a non-zero status is found. */
681
682 static void
683 do_wait (prog)
684      char *prog;
685 {
686   int status;
687
688   wait (&status);
689   if (status)
690     {
691       int sig = WTERMSIG (status);
692       int ret;
693
694       if (sig != -1 && sig != 0)
695         {
696           error ("%s terminated with signal %d [%s]%s",
697                  prog,
698                  sig,
699                  sys_siglist[sig],
700                  (status & 0200) ? ", core dumped" : "");
701
702           my_exit (127);
703         }
704
705       ret = WEXITSTATUS (status);
706       if (ret != -1 && ret != 0)
707         {
708           error ("%s returned %d exit status", prog, ret);
709           my_exit (ret);
710         }
711     }
712 }
713
714 \f
715 /* Fork and execute a program, and wait for the reply.  */
716
717 static void
718 fork_execute (prog, argv)
719      char *prog;
720      char **argv;
721 {
722   int pid;
723   void (*int_handler) PROTO((int));
724   void (*quit_handler) PROTO((int));
725
726   if (vflag || debug)
727     {
728       char **p_argv;
729       char *str;
730
731       fprintf (stderr, "%s", prog);
732       for (p_argv = &argv[1]; (str = *p_argv) != (char *)0; p_argv++)
733         fprintf (stderr, " %s", str);
734
735       fprintf (stderr, "\n");
736     }
737
738   fflush (stdout);
739   fflush (stderr);
740
741   pid = vfork ();
742   if (pid == -1)
743     fatal_perror ("vfork");
744
745   if (pid == 0)                 /* child context */
746     {
747       execvp (prog, argv);
748       fatal_perror ("Execute %s", prog);
749     }
750
751   int_handler  = (void (*)PROTO((int)))signal (SIGINT,  SIG_IGN);
752   quit_handler = (void (*)PROTO((int)))signal (SIGQUIT, SIG_IGN);
753
754   do_wait (prog);
755
756   signal (SIGINT,  int_handler);
757   signal (SIGQUIT, quit_handler);
758 }
759
760 \f
761 /* Unlink a file unless we are debugging.  */
762
763 static void
764 maybe_unlink (file)
765      char *file;
766 {
767   if (!debug)
768     unlink (file);
769   else
770     fprintf (stderr, "[Leaving %s]\n", file);
771 }
772
773 \f
774 /* Add a name to a linked list.  */
775
776 static void
777 add_to_list (head_ptr, name)
778      struct head *head_ptr;
779      char *name;
780 {
781   struct id *newid = (struct id *) xcalloc (sizeof (*newid) + strlen (name), 1);
782   static long sequence_number = 0;
783   newid->sequence = ++sequence_number;
784   strcpy (newid->name, name);
785
786   if (head_ptr->first)
787     head_ptr->last->next = newid;
788   else
789     head_ptr->first = newid;
790
791   head_ptr->last = newid;
792   head_ptr->number++;
793 }
794
795 /* Write: `prefix', the names on list LIST, `suffix'.  */
796
797 static void
798 write_list (stream, prefix, list)
799      FILE *stream;
800      char *prefix;
801      struct id *list;
802 {
803   while (list)
804     {
805       fprintf (stream, "%sx%d,\n", prefix, list->sequence);
806       list = list->next;
807     }
808 }
809
810 static void
811 write_list_with_asm (stream, prefix, list)
812      FILE *stream;
813      char *prefix;
814      struct id *list;
815 {
816   while (list)
817     {
818       fprintf (stream, "%sx%d asm (\"%s\");\n",
819                prefix, list->sequence, list->name);
820       list = list->next;
821     }
822 }
823
824 /* Write the constructor/destructor tables. */
825
826 static void
827 write_c_file (stream, name)
828      FILE *stream;
829      char *name;
830 {
831   /* Write the tables as C code  */
832
833   fprintf (stream, "typedef void entry_pt();\n\n");
834     
835   write_list_with_asm (stream, "entry_pt ", constructors);
836     
837   fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
838   fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
839   write_list (stream, "\t", constructors);
840   fprintf (stream, "\t0\n};\n\n");
841
842   write_list_with_asm (stream, "entry_pt ", destructors);
843
844   fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
845   fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
846   write_list (stream, "\t", destructors);
847   fprintf (stream, "\t0\n};\n\n");
848
849   fprintf (stream, "extern entry_pt __main;\n");
850   fprintf (stream, "entry_pt *__main_reference = __main;\n\n");
851 }
852
853 \f
854 #ifndef OBJECT_FORMAT_ROSE
855
856 /* OSF/rose specific version to scan the name list of the loaded
857    program for the symbols g++ uses for static constructors and
858    destructors.
859
860    The constructor table begins at __CTOR_LIST__ and contains a count
861    of the number of pointers (or -1 if the constructors are built in a
862    separate section by the linker), followed by the pointers to the
863    constructor functions, terminated with a null pointer.  The
864    destructor table has the same format, and begins at __DTOR_LIST__.  */
865
866 static void
867 scan_prog_file (prog_name, which_pass)
868      char *prog_name;
869      enum pass which_pass;
870 {
871   void (*int_handler) PROTO((int));
872   void (*quit_handler) PROTO((int));
873   char *nm_argv[4];
874   int pid;
875   int argc = 0;
876   int pipe_fd[2];
877   char *p, buf[1024];
878   FILE *inf;
879
880   if (which_pass != PASS_FIRST)
881     return;
882
883   nm_argv[ argc++ ] = "nm";
884   if (NM_FLAGS[0] != '\0')
885     nm_argv[ argc++ ] = NM_FLAGS;
886
887   nm_argv[ argc++ ] = prog_name;
888   nm_argv[ argc++ ] = (char *)0;
889
890   if (pipe (pipe_fd) < 0)
891     fatal_perror ("pipe");
892
893   inf = fdopen (pipe_fd[0], "r");
894   if (inf == (FILE *)0)
895     fatal_perror ("fdopen");
896
897   /* Trace if needed.  */
898   if (vflag)
899     {
900       char **p_argv;
901       char *str;
902
903       fprintf (stderr, "%s", nm_file_name);
904       for (p_argv = &nm_argv[1]; (str = *p_argv) != (char *)0; p_argv++)
905         fprintf (stderr, " %s", str);
906
907       fprintf (stderr, "\n");
908     }
909
910   fflush (stdout);
911   fflush (stderr);
912
913   /* Spawn child nm on pipe */
914   pid = vfork ();
915   if (pid == -1)
916     fatal_perror ("vfork");
917
918   if (pid == 0)                 /* child context */
919     {
920       /* setup stdout */
921       if (dup2 (pipe_fd[1], 1) < 0)
922         fatal_perror ("Dup2 (%d, 1)", pipe_fd[1]);
923
924       if (close (pipe_fd[0]) < 0)
925         fatal_perror ("Close (%d)", pipe_fd[0]);
926
927       if (close (pipe_fd[1]) < 0)
928         fatal_perror ("Close (%d)", pipe_fd[1]);
929
930       execv (nm_file_name, nm_argv);
931       fatal_perror ("Execute %s", nm_file_name);
932     }
933
934   /* Parent context from here on.  */
935   int_handler  = (void (*)PROTO((int)))signal (SIGINT,  SIG_IGN);
936   quit_handler = (void (*)PROTO((int)))signal (SIGQUIT, SIG_IGN);
937
938   if (close (pipe_fd[1]) < 0)
939     fatal_perror ("Close (%d)", pipe_fd[1]);
940
941   if (debug)
942     fprintf (stderr, "\nnm output with constructors/destructors.\n");
943
944   /* Read each line of nm output.  */
945   while (fgets (buf, sizeof buf, inf) != (char *)0)
946     {
947       int ch, ch2;
948       char *start;
949       char *end;
950
951       /* If it contains a constructor or destructor name, add the name
952          to the appropriate list. */
953
954       for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
955         ;
956
957       if (ch == '\0' || ch == '\n')
958         continue;
959
960       start = p;
961       while ((ch = *p) == '_')  /* skip any extra '_' inserted */
962         p++;
963
964       for (end = p; (ch2 = *end) != '\0' && !isspace (ch2); end++)
965         ;
966
967       *end = '\0';
968       if (ch == 'G')
969         {
970           if (! strncmp (p, "GLOBAL_$I$", 10))
971             add_to_list (&constructors, p-1);
972
973           else if (! strncmp (p, "GLOBAL_$D$", 10))
974             add_to_list (&destructors, p-1);
975
976           else                          /* not a constructor or destructor */
977             continue;
978         }
979
980       else if (ch == 's' && (p - start) >= 2)
981         {
982           if (! strncmp (p, "sti__", 5))
983             add_to_list (&constructors, p-2);
984
985           else if (! strncmp (p, "std__", 5))
986             add_to_list (&destructors, p-2);
987
988           else                          /* not a constructor or destructor */
989             continue;
990         }
991
992       else
993         continue;
994
995       if (debug)
996         fprintf (stderr, "\t%s\n", buf);
997     }
998
999   if (debug)
1000     fprintf (stderr, "\n");
1001
1002   if (fclose (inf) != 0)
1003     fatal_perror ("fclose of pipe");
1004
1005   do_wait (nm_file_name);
1006
1007   signal (SIGINT,  int_handler);
1008   signal (SIGQUIT, quit_handler);
1009 }
1010
1011 #endif /* !OBJECT_FORMAT_ROSE */
1012
1013 \f
1014 /*
1015  * OSF/rose specific stuff.
1016  */
1017
1018 #ifdef OBJECT_FORMAT_ROSE
1019
1020 /* Union of the various load commands */
1021
1022 typedef union load_union
1023 {
1024   ldc_header_t                  hdr;    /* common header */
1025   load_cmd_map_command_t        map;    /* map indexing other load cmds */
1026   interpreter_command_t         iprtr;  /* interpereter pathname */
1027   strings_command_t             str;    /* load commands strings section */
1028   region_command_t              region; /* region load command */
1029   reloc_command_t               reloc;  /* relocation section */
1030   package_command_t             pkg;    /* package load command */
1031   symbols_command_t             sym;    /* symbol sections */
1032   entry_command_t               ent;    /* program start section */
1033   gen_info_command_t            info;   /* object information */
1034   func_table_command_t          func;   /* function constructors/destructors */
1035 } load_union_t;
1036
1037 /* Structure to point to load command and data section in memory.  */
1038
1039 typedef struct load_all
1040 {
1041   load_union_t *load;                   /* load command */
1042   char *section;                        /* pointer to section */
1043 } load_all_t;
1044
1045 /* Structure to contain information about a file mapped into memory.  */
1046
1047 struct file_info
1048 {
1049   char *start;                          /* start of map */
1050   char *name;                           /* filename */
1051   long  size;                           /* size of the file */
1052   long  rounded_size;                   /* size rounded to page boundary */
1053   int   fd;                             /* file descriptor */
1054   int   rw;                             /* != 0 if opened read/write */
1055   int   use_mmap;                       /* != 0 if mmap'ed */
1056 };
1057
1058 extern int decode_mach_o_hdr            PROTO(( void *in_bufp,
1059                                                 size_t in_bufsize,
1060                                                 unsigned long hdr_version,
1061                                                 mo_header_t *headerp ));
1062
1063 extern int encode_mach_o_hdr            PROTO(( mo_header_t *headerp,
1064                                                 void *out_bufp,
1065                                                 size_t out_bufsize ));
1066
1067 static void bad_header                  PROTO(( int status ));
1068
1069 static void print_header                PROTO(( mo_header_t *hdr_ptr ));
1070
1071 static void print_load_command          PROTO(( load_union_t *load_hdr,
1072                                                 size_t offset,
1073                                                 int number ));
1074
1075 static void add_func_table              PROTO(( mo_header_t *hdr_p,
1076                                                 load_all_t *load_array,
1077                                                 symbol_info_t *sym,
1078                                                 int type ));
1079
1080 static struct file_info *read_file      PROTO(( char *, int, int ));
1081
1082 static void end_file                    PROTO(( struct file_info * ));
1083
1084 \f
1085 /* OSF/rose specific version to scan the name list of the loaded
1086    program for the symbols g++ uses for static constructors and
1087    destructors.
1088
1089    The constructor table begins at __CTOR_LIST__ and contains a count
1090    of the number of pointers (or -1 if the constructors are built in a
1091    separate section by the linker), followed by the pointers to the
1092    constructor functions, terminated with a null pointer.  The
1093    destructor table has the same format, and begins at __DTOR_LIST__.  */
1094
1095 static void
1096 scan_prog_file (prog_name, which_pass)
1097      char *prog_name;
1098      enum pass which_pass;
1099 {
1100   char *obj;
1101   mo_header_t hdr;
1102   load_all_t *load_array;
1103   load_all_t *load_end;
1104   load_all_t *load_cmd;
1105   int symbol_load_cmds;
1106   off_t offset;
1107   int i;
1108   int num_syms;
1109   int status;
1110   char *str_sect;
1111   struct file_info *obj_file;
1112   int prog_fd;
1113   mo_lcid_t cmd_strings   = -1;
1114   symbol_info_t *main_sym = 0;
1115   int rw                  = (which_pass != PASS_FIRST);
1116
1117   prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY);
1118   if (prog_fd < 0)
1119     fatal_perror ("Can't read %s", prog_name);
1120
1121   obj_file = read_file (prog_name, prog_fd, rw);
1122   obj = obj_file->start;
1123
1124   status = decode_mach_o_hdr (obj, MO_SIZEOF_RAW_HDR, MOH_HEADER_VERSION, &hdr);
1125   if (status != MO_HDR_CONV_SUCCESS)
1126     bad_header (status);
1127
1128
1129   /* Do some basic sanity checks.  Note we explicitly use the big endian magic number,
1130      since the hardware will automatically swap bytes for us on loading little endian
1131      integers.  */
1132
1133 #ifndef CROSS_COMPILE
1134   if (hdr.moh_magic != MOH_MAGIC_MSB
1135       || hdr.moh_header_version != MOH_HEADER_VERSION
1136       || hdr.moh_byte_order != OUR_BYTE_ORDER
1137       || hdr.moh_data_rep_id != OUR_DATA_REP_ID
1138       || hdr.moh_cpu_type != OUR_CPU_TYPE
1139       || hdr.moh_cpu_subtype != OUR_CPU_SUBTYPE
1140       || hdr.moh_vendor_type != OUR_VENDOR_TYPE)
1141     {
1142       fatal ("incompatibilities exist between object file & expected values.");
1143     }
1144 #endif
1145
1146   if (debug)
1147     print_header (&hdr);
1148
1149   offset = hdr.moh_first_cmd_off;
1150   load_end = load_array
1151     = (load_all_t *) xcalloc (sizeof (load_all_t), hdr.moh_n_load_cmds + 2);
1152
1153   /* Build array of load commands, calculating the offsets */
1154   for (i = 0; i < hdr.moh_n_load_cmds; i++)
1155     {
1156       load_union_t *load_hdr;           /* load command header */
1157
1158       load_cmd = load_end++;
1159       load_hdr = (load_union_t *) (obj + offset);
1160
1161       /* If modifing the program file, copy the header.  */
1162       if (rw)
1163         {
1164           load_union_t *ptr = (load_union_t *) xmalloc (load_hdr->hdr.ldci_cmd_size);
1165           memcpy (ptr, load_hdr, load_hdr->hdr.ldci_cmd_size);
1166           load_hdr = ptr;
1167
1168           /* null out old command map, because we will rewrite at the end.  */
1169           if (ptr->hdr.ldci_cmd_type == LDC_CMD_MAP)
1170             {
1171               cmd_strings = ptr->map.lcm_ld_cmd_strings;
1172               ptr->hdr.ldci_cmd_type = LDC_UNDEFINED;
1173             }
1174         }
1175
1176       load_cmd->load = load_hdr;
1177       if (load_hdr->hdr.ldci_section_off > 0)
1178         load_cmd->section = obj + load_hdr->hdr.ldci_section_off;
1179
1180       if (debug)
1181         print_load_command (load_hdr, offset, i);
1182
1183       offset += load_hdr->hdr.ldci_cmd_size;
1184     }
1185
1186   /* If the last command is the load command map and is not undefined,
1187      decrement the count of load commands.  */
1188   if (rw && load_end[-1].load->hdr.ldci_cmd_type == LDC_UNDEFINED)
1189     {
1190       load_end--;
1191       hdr.moh_n_load_cmds--;
1192     }
1193
1194   /* Go through and process each symbol table section.  */
1195   symbol_load_cmds = 0;
1196   for (load_cmd = load_array; load_cmd < load_end; load_cmd++)
1197     {
1198       load_union_t *load_hdr = load_cmd->load;
1199
1200       if (load_hdr->hdr.ldci_cmd_type == LDC_SYMBOLS)
1201         {
1202           symbol_load_cmds++;
1203
1204           if (debug)
1205             {
1206               char *kind = "uknown";
1207
1208               switch (load_hdr->sym.symc_kind)
1209                 {
1210                 case SYMC_IMPORTS:         kind = "imports"; break;
1211                 case SYMC_DEFINED_SYMBOLS: kind = "defined"; break;
1212                 case SYMC_STABS:           kind = "stabs";   break;
1213                 }
1214
1215               fprintf (stderr, "\nProcessing symbol table #%d, offset = 0x%.8lx, kind = %s\n",
1216                        symbol_load_cmds, load_hdr->hdr.ldci_section_off, kind);
1217             }
1218
1219           if (load_hdr->sym.symc_kind != SYMC_DEFINED_SYMBOLS)
1220             continue;
1221
1222           str_sect = load_array[ load_hdr->sym.symc_strings_section ].section;
1223           if (str_sect == (char *)0)
1224             fatal ("string section missing");
1225
1226           if (load_cmd->section == (char *)0)
1227             fatal ("section pointer missing");
1228
1229           num_syms = load_hdr->sym.symc_nentries;
1230           for (i = 0; i < num_syms; i++)
1231             {
1232               symbol_info_t *sym = ((symbol_info_t *) load_cmd->section) + i;
1233               char *name = sym->si_name.symbol_name + str_sect;
1234               char *name_start = name;
1235
1236               if (name[0] != '_')
1237                 continue;
1238
1239               while (*++name == '_')    /* skip any extra '_' inserted */
1240                 ;
1241
1242               if (rw)
1243                 {
1244                   if (*name != 'm' || (name - name_start) < 2
1245                       || strcmp (name, "main"))
1246                     continue;
1247
1248                   main_sym = sym;
1249                 }
1250
1251               else if (*name == 'G')
1252                 {
1253                   if (! strncmp (name, "GLOBAL_$I$", 10))
1254                     add_to_list (&constructors, name_start);
1255
1256                   else if (! strncmp (name, "GLOBAL_$D$", 10))
1257                     add_to_list (&destructors, name_start);
1258
1259                   else          /* not a constructor or destructor */
1260                     continue;
1261                 }
1262
1263               else if (*name == 's' && (name - name_start) > 2)
1264                 {
1265                   if (! strncmp (name, "sti__", 5))
1266                     add_to_list (&constructors, name_start);
1267
1268                   else if (! strncmp (name, "std__", 5))
1269                     add_to_list (&destructors, name_start);
1270
1271                   else          /* not a constructor or destructor */
1272                     continue;
1273                 }
1274
1275               else
1276                 continue;
1277
1278               if (debug)
1279                 fprintf (stderr, "\ttype = 0x%.4x, sc = 0x%.2x, flags = 0x%.8x, name = %.30s\n",
1280                          sym->si_type, sym->si_sc_type, sym->si_flags, name);
1281             }
1282         }
1283     }
1284
1285   if (symbol_load_cmds == 0)
1286     fatal ("no symbol table found.");
1287
1288   /* Update the program file now, rewrite header and load commands.  At present,
1289      we assume that there is enough space after the last load command to insert
1290      one more.  Since the first section written out is page aligned, and the
1291      number of load commands is small, this is ok for the present.  */
1292
1293   if (rw)
1294     {
1295       load_union_t *load_map;
1296       size_t size;
1297
1298       if (cmd_strings == -1)
1299         fatal ("no cmd_strings found.");
1300
1301       /* Add __main to initializer list.  */
1302       if (main_sym != (symbol_info_t *)0)
1303         add_func_table (&hdr, load_array, main_sym, FNTC_INITIALIZATION);
1304
1305       if (debug)
1306         fprintf (stderr, "\nUpdating header and load commands.\n\n");
1307
1308       hdr.moh_n_load_cmds++;
1309       size = sizeof (load_cmd_map_command_t) + (sizeof (mo_offset_t) * (hdr.moh_n_load_cmds - 1));
1310
1311       /* Create new load command map.  */
1312       if (debug)
1313         fprintf (stderr, "load command map, %d cmds, new size %ld.\n",
1314                  (int)hdr.moh_n_load_cmds, (long)size);
1315
1316       load_map = (load_union_t *) xcalloc (1, size);
1317       load_map->map.ldc_header.ldci_cmd_type = LDC_CMD_MAP;
1318       load_map->map.ldc_header.ldci_cmd_size = size;
1319       load_map->map.lcm_ld_cmd_strings = cmd_strings;
1320       load_map->map.lcm_nentries = hdr.moh_n_load_cmds;
1321       load_array[hdr.moh_n_load_cmds-1].load = load_map;
1322
1323       offset = hdr.moh_first_cmd_off;
1324       for (i = 0; i < hdr.moh_n_load_cmds; i++)
1325         {
1326           load_map->map.lcm_map[i] = offset;
1327           if (load_array[i].load->hdr.ldci_cmd_type == LDC_CMD_MAP)
1328             hdr.moh_load_map_cmd_off = offset;
1329
1330           offset += load_array[i].load->hdr.ldci_cmd_size;
1331         }
1332
1333       hdr.moh_sizeofcmds = offset - MO_SIZEOF_RAW_HDR;
1334
1335       if (debug)
1336         print_header (&hdr);
1337
1338       /* Write header */
1339       status = encode_mach_o_hdr (&hdr, obj, MO_SIZEOF_RAW_HDR);
1340       if (status != MO_HDR_CONV_SUCCESS)
1341         bad_header (status);
1342
1343       if (debug)
1344         fprintf (stderr, "writing load commands.\n\n");
1345
1346       /* Write load commands */
1347       offset = hdr.moh_first_cmd_off;
1348       for (i = 0; i < hdr.moh_n_load_cmds; i++)
1349         {
1350           load_union_t *load_hdr = load_array[i].load;
1351           size_t size = load_hdr->hdr.ldci_cmd_size;
1352
1353           if (debug)
1354             print_load_command (load_hdr, offset, i);
1355
1356           memcpy (obj + offset, load_hdr, size);
1357           offset += size;
1358         }
1359     }
1360
1361   end_file (obj_file);
1362
1363   if (close (prog_fd))
1364     fatal_perror ("Can't close %s", prog_name);
1365
1366   if (debug)
1367     fprintf (stderr, "\n");
1368 }
1369
1370 \f
1371 /* Add a function table to the load commands to call a function
1372    on initition or termination of the process.  */
1373
1374 static void
1375 add_func_table (hdr_p, load_array, sym, type)
1376      mo_header_t *hdr_p;                /* pointer to global header */
1377      load_all_t *load_array;            /* array of ptrs to load cmds */
1378      symbol_info_t *sym;                /* pointer to symbol entry */
1379      int type;                          /* fntc_type value */
1380 {
1381   /* Add a new load command.  */
1382   int num_cmds = ++hdr_p->moh_n_load_cmds;
1383   int load_index = num_cmds - 1;
1384   size_t size = sizeof (func_table_command_t) + sizeof (mo_addr_t);
1385   load_union_t *ptr = xcalloc (1, size);
1386   load_all_t *load_cmd;
1387   int i;
1388
1389   /* Set the unresolved address bit in the header to force the loader to be
1390      used, since kernel exec does not call the initialization functions.  */
1391   hdr_p->moh_flags |= MOH_UNRESOLVED_F;
1392
1393   load_cmd = &load_array[load_index];
1394   load_cmd->load = ptr;
1395   load_cmd->section = (char *)0;
1396
1397   /* Fill in func table load command.  */
1398   ptr->func.ldc_header.ldci_cmd_type = LDC_FUNC_TABLE;
1399   ptr->func.ldc_header.ldci_cmd_size = size;
1400   ptr->func.ldc_header.ldci_section_off = 0;
1401   ptr->func.ldc_header.ldci_section_len = 0;
1402   ptr->func.fntc_type = type;
1403   ptr->func.fntc_nentries = 1;
1404
1405   /* copy address, turn it from abs. address to (region,offset) if necessary.  */
1406   /* Is the symbol already expressed as (region, offset)?  */
1407   if ((sym->si_flags & SI_ABSOLUTE_VALUE_F) == 0)
1408     {
1409       ptr->func.fntc_entry_loc[i].adr_lcid = sym->si_value.def_val.adr_lcid;
1410       ptr->func.fntc_entry_loc[i].adr_sctoff = sym->si_value.def_val.adr_sctoff;
1411     }
1412
1413   /* If not, figure out which region it's in.  */
1414   else
1415     {
1416       mo_vm_addr_t addr = sym->si_value.abs_val;
1417       int found = 0;
1418
1419       for (i = 0; i < load_index; i++)
1420         {
1421           if (load_array[i].load->hdr.ldci_cmd_type == LDC_REGION)
1422             {
1423               region_command_t *region_ptr = &load_array[i].load->region;
1424
1425               if ((region_ptr->regc_flags & REG_ABS_ADDR_F) != 0
1426                   && addr >= region_ptr->regc_addr.vm_addr
1427                   && addr <= region_ptr->regc_addr.vm_addr + region_ptr->regc_vm_size)
1428                 {
1429                   ptr->func.fntc_entry_loc[0].adr_lcid = i;
1430                   ptr->func.fntc_entry_loc[0].adr_sctoff = addr - region_ptr->regc_addr.vm_addr;
1431                   found++;
1432                   break;
1433                 }
1434             }
1435         }
1436
1437       if (!found)
1438         fatal ("could not convert 0x%l.8x into a region", addr);
1439     }
1440
1441   if (debug)
1442     fprintf (stderr,
1443              "%s function, region %d, offset = %ld (0x%.8lx)\n",
1444              (type == FNTC_INITIALIZATION) ? "init" : "term",
1445              (int)ptr->func.fntc_entry_loc[i].adr_lcid,
1446              (long)ptr->func.fntc_entry_loc[i].adr_sctoff,
1447              (long)ptr->func.fntc_entry_loc[i].adr_sctoff);
1448
1449 }
1450
1451 \f
1452 /* Print the global header for an OSF/rose object.  */
1453
1454 static void
1455 print_header (hdr_ptr)
1456      mo_header_t *hdr_ptr;
1457 {
1458   fprintf (stderr, "\nglobal header:\n");
1459   fprintf (stderr, "\tmoh_magic            = 0x%.8lx\n", hdr_ptr->moh_magic);
1460   fprintf (stderr, "\tmoh_major_version    = %d\n", (int)hdr_ptr->moh_major_version);
1461   fprintf (stderr, "\tmoh_minor_version    = %d\n", (int)hdr_ptr->moh_minor_version);
1462   fprintf (stderr, "\tmoh_header_version   = %d\n", (int)hdr_ptr->moh_header_version);
1463   fprintf (stderr, "\tmoh_max_page_size    = %d\n", (int)hdr_ptr->moh_max_page_size);
1464   fprintf (stderr, "\tmoh_byte_order       = %d\n", (int)hdr_ptr->moh_byte_order);
1465   fprintf (stderr, "\tmoh_data_rep_id      = %d\n", (int)hdr_ptr->moh_data_rep_id);
1466   fprintf (stderr, "\tmoh_cpu_type         = %d\n", (int)hdr_ptr->moh_cpu_type);
1467   fprintf (stderr, "\tmoh_cpu_subtype      = %d\n", (int)hdr_ptr->moh_cpu_subtype);
1468   fprintf (stderr, "\tmoh_vendor_type      = %d\n", (int)hdr_ptr->moh_vendor_type);
1469   fprintf (stderr, "\tmoh_load_map_cmd_off = %d\n", (int)hdr_ptr->moh_load_map_cmd_off);
1470   fprintf (stderr, "\tmoh_first_cmd_off    = %d\n", (int)hdr_ptr->moh_first_cmd_off);
1471   fprintf (stderr, "\tmoh_sizeofcmds       = %d\n", (int)hdr_ptr->moh_sizeofcmds);
1472   fprintf (stderr, "\tmon_n_load_cmds      = %d\n", (int)hdr_ptr->moh_n_load_cmds);
1473   fprintf (stderr, "\tmoh_flags            = 0x%.8lx", (long)hdr_ptr->moh_flags);
1474
1475   if (hdr_ptr->moh_flags & MOH_RELOCATABLE_F)
1476     fprintf (stderr, ", relocatable");
1477
1478   if (hdr_ptr->moh_flags & MOH_LINKABLE_F)
1479     fprintf (stderr, ", linkable");
1480
1481   if (hdr_ptr->moh_flags & MOH_EXECABLE_F)
1482     fprintf (stderr, ", execable");
1483
1484   if (hdr_ptr->moh_flags & MOH_EXECUTABLE_F)
1485     fprintf (stderr, ", executable");
1486
1487   if (hdr_ptr->moh_flags & MOH_UNRESOLVED_F)
1488     fprintf (stderr, ", unresolved");
1489
1490   fprintf (stderr, "\n\n");
1491   return;
1492 }
1493
1494 \f
1495 /* Print a short summary of a load command.  */
1496
1497 static void
1498 print_load_command (load_hdr, offset, number)
1499      load_union_t *load_hdr;
1500      size_t offset;
1501      int number;
1502 {
1503   mo_long_t type = load_hdr->hdr.ldci_cmd_type;
1504   char *type_str = (char *)0;
1505
1506   switch (type)
1507     {
1508     case LDC_UNDEFINED:   type_str = "UNDEFINED";       break;
1509     case LDC_CMD_MAP:     type_str = "CMD_MAP";         break;
1510     case LDC_INTERPRETER: type_str = "INTERPRETER";     break;
1511     case LDC_STRINGS:     type_str = "STRINGS";         break;
1512     case LDC_REGION:      type_str = "REGION";          break;
1513     case LDC_RELOC:       type_str = "RELOC";           break;
1514     case LDC_PACKAGE:     type_str = "PACKAGE";         break;
1515     case LDC_SYMBOLS:     type_str = "SYMBOLS";         break;
1516     case LDC_ENTRY:       type_str = "ENTRY";           break;
1517     case LDC_FUNC_TABLE:  type_str = "FUNC_TABLE";      break;
1518     case LDC_GEN_INFO:    type_str = "GEN_INFO";        break;
1519     }
1520
1521   fprintf (stderr,
1522            "cmd %2d, sz: 0x%.2lx, coff: 0x%.3lx, doff: 0x%.6lx, dlen: 0x%.6lx",
1523            number,
1524            (long) load_hdr->hdr.ldci_cmd_size,
1525            (long) offset,
1526            (long) load_hdr->hdr.ldci_section_off,
1527            (long) load_hdr->hdr.ldci_section_len);
1528
1529   if (type_str == (char *)0)
1530     fprintf (stderr, ", ty: unknown (%ld)\n", (long) type);
1531
1532   else if (type != LDC_REGION)
1533     fprintf (stderr, ", ty: %s\n", type_str);
1534
1535   else
1536     {
1537       char *region = "";
1538       switch (load_hdr->region.regc_usage_type)
1539         {
1540         case REG_TEXT_T:        region = ", .text";     break;
1541         case REG_DATA_T:        region = ", .data";     break;
1542         case REG_BSS_T:         region = ", .bss";      break;
1543         case REG_GLUE_T:        region = ", .glue";     break;
1544 #if defined (REG_RDATA_T) && defined (REG_SDATA_T) && defined (REG_SBSS_T) /*mips*/
1545         case REG_RDATA_T:       region = ", .rdata";    break;
1546         case REG_SDATA_T:       region = ", .sdata";    break;
1547         case REG_SBSS_T:        region = ", .sbss";     break;
1548 #endif
1549         }
1550
1551       fprintf (stderr, ", ty: %s, vaddr: 0x%.8lx, vlen: 0x%.6lx%s\n",
1552                type_str,
1553                (long) load_hdr->region.regc_vm_addr,
1554                (long) load_hdr->region.regc_vm_size,
1555                region);
1556     }
1557
1558   return;
1559 }
1560
1561 \f
1562 /* Fatal error when {en,de}code_mach_o_header fails.  */
1563
1564 static void
1565 bad_header (status)
1566      int status;
1567 {
1568   char *msg = (char *)0;
1569
1570   switch (status)
1571     {
1572     case MO_ERROR_BAD_MAGIC:            msg = "bad magic number";               break;
1573     case MO_ERROR_BAD_HDR_VERS:         msg = "bad header version";             break;
1574     case MO_ERROR_BAD_RAW_HDR_VERS:     msg = "bad raw header version";         break;
1575     case MO_ERROR_BUF2SML:              msg = "raw header buffer too small";    break;
1576     case MO_ERROR_OLD_RAW_HDR_FILE:     msg = "old raw header file";            break;
1577     case MO_ERROR_UNSUPPORTED_VERS:     msg = "unsupported version";            break;
1578     }
1579
1580   if (msg == (char *)0)
1581     fatal ("unknown {de,en}code_mach_o_hdr return value %d", status);
1582   else
1583     fatal ("%s", msg);
1584 }
1585
1586 \f
1587 /* Read a file into a memory buffer.  */
1588
1589 static struct file_info *
1590 read_file (name, fd, rw)
1591      char *name;                /* filename */
1592      int fd;                    /* file descriptor */
1593      int rw;                    /* read/write */
1594 {
1595   struct stat stat_pkt;
1596   struct file_info *p = (struct file_info *) xcalloc (sizeof (struct file_info), 1);
1597 #ifdef USE_MMAP
1598   static int page_size;
1599 #endif
1600
1601   if (fstat (fd, &stat_pkt) < 0)
1602     fatal_perror ("fstat %s", name);
1603
1604   p->name         = name;
1605   p->size         = stat_pkt.st_size;
1606   p->rounded_size = stat_pkt.st_size;
1607   p->fd           = fd;
1608   p->rw           = rw;
1609
1610 #ifdef USE_MMAP
1611   if (debug)
1612     fprintf (stderr, "mmap %s, %s\n", name, (rw) ? "read/write" : "read-only");
1613
1614   if (page_size == 0)
1615     page_size = sysconf (_SC_PAGE_SIZE);
1616
1617   p->rounded_size = ((p->size + page_size - 1) / page_size) * page_size;
1618   p->start = mmap ((caddr_t)0,
1619                    (rw) ? p->rounded_size : p->size,
1620                    (rw) ? (PROT_READ | PROT_WRITE) : PROT_READ,
1621                    MAP_FILE | MAP_VARIABLE | MAP_SHARED,
1622                    fd,
1623                    0L);
1624
1625   if (p->start != (char *)0 && p->start != (char *)-1)
1626     p->use_mmap = 1;
1627
1628   else
1629 #endif /* USE_MMAP */
1630     {
1631       long len;
1632
1633       if (debug)
1634         fprintf (stderr, "read %s\n", name);
1635
1636       p->use_mmap = 0;
1637       p->start = xmalloc (p->size);
1638       if (lseek (fd, 0L, SEEK_SET) < 0)
1639         fatal_perror ("lseek to 0 on %s", name);
1640
1641       len = read (fd, p->start, p->size);
1642       if (len < 0)
1643         fatal_perror ("read %s", name);
1644
1645       if (len != p->size)
1646         fatal ("read %ld bytes, expected %ld, from %s", len, p->size, name);
1647     }
1648
1649   return p;
1650 }
1651
1652 \f
1653 /* Do anything necessary to write a file back from memory.  */
1654
1655 static void
1656 end_file (ptr)
1657      struct file_info *ptr;     /* file information block */
1658 {
1659 #ifdef USE_MMAP
1660   if (ptr->use_mmap)
1661     {
1662       if (ptr->rw)
1663         {
1664           if (debug)
1665             fprintf (stderr, "msync %s\n", ptr->name);
1666
1667           if (msync (ptr->start, ptr->rounded_size, MS_ASYNC))
1668             fatal_perror ("msync %s", ptr->name);
1669         }
1670
1671       if (debug)
1672         fprintf (stderr, "munmap %s\n", ptr->name);
1673
1674       if (munmap (ptr->start, ptr->size))
1675         fatal_perror ("munmap %s", ptr->name);
1676     }
1677   else
1678 #endif /* USE_MMAP */
1679     {
1680       if (ptr->rw)
1681         {
1682           long len;
1683
1684           if (debug)
1685             fprintf (stderr, "write %s\n", ptr->name);
1686
1687           if (lseek (ptr->fd, 0L, SEEK_SET) < 0)
1688             fatal_perror ("lseek to 0 on %s", ptr->name);
1689
1690           len = write (ptr->fd, ptr->start, ptr->size);
1691           if (len < 0)
1692             fatal_perror ("read %s", ptr->name);
1693
1694           if (len != ptr->size)
1695             fatal ("wrote %ld bytes, expected %ld, to %s", len, ptr->size, ptr->name);
1696         }
1697
1698       free ((generic *)ptr->start);
1699     }
1700
1701   free ((generic *)ptr);
1702 }
1703
1704 #endif /* OBJECT_FORMAT_ROSE */