Make all callers of malloc or realloc (including via obstacks)
[external/binutils.git] / bfd / sunos.c
1 /* BFD backend for SunOS binaries.
2    Copyright (C) 1990-1991 Free Software Foundation, Inc.
3    Written by Cygnus Support.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #define ARCH 32
22 #define TARGETNAME "a.out-sunos-big"
23 #define MY(OP) CAT(sunos_big_,OP)
24
25 #include "bfd.h"
26
27 /* Static routines defined in this file.  */
28
29 struct external_nlist;
30
31 static boolean sunos_read_dynamic_info PARAMS ((bfd *));
32 static bfd_size_type MY(read_dynamic_symbols)
33      PARAMS ((bfd *, struct external_nlist **, char **, bfd_size_type *));
34 static bfd_size_type MY(read_dynamic_relocs) PARAMS ((bfd *, PTR *));
35
36 #define MY_read_dynamic_symbols MY(read_dynamic_symbols)
37 #define MY_read_dynamic_relocs MY(read_dynamic_relocs)
38
39 /* Include the usual a.out support.  */
40 #include "aoutf1.h"
41
42 /* SunOS shared library support.  We store a pointer to this structure
43    in obj_aout_dynamic_info (abfd).  */
44
45 struct sunos_dynamic_info
46 {
47   /* Whether we found any dynamic information.  */
48   boolean valid;
49   /* Dynamic information.  */
50   struct internal_sun4_dynamic_link dyninfo;
51   /* Number of dynamic symbols.  */
52   bfd_size_type dynsym_count;
53   /* Read in nlists for dynamic symbols.  */
54   struct external_nlist *dynsym;
55   /* Read in dynamic string table.  */
56   char *dynstr;
57   /* Number of dynamic relocs.  */
58   bfd_size_type dynrel_count;
59   /* Read in dynamic relocs.  This may be reloc_std_external or
60      reloc_ext_external.  */
61   PTR dynrel;
62 };
63
64 /* Read in the basic dynamic information.  This locates the __DYNAMIC
65    structure and uses it to find the dynamic_link structure.  It
66    creates and saves a sunos_dynamic_info structure.  If it can't find
67    __DYNAMIC, it sets the valid field of the sunos_dynamic_info
68    structure to false to avoid doing this work again.  */
69
70 static boolean
71 sunos_read_dynamic_info (abfd)
72      bfd *abfd;
73 {
74   struct sunos_dynamic_info *info;
75   struct external_nlist dynsym;
76   char buf[sizeof "__DYNAMIC"];
77   asection *dynsec;
78   file_ptr dynoff;
79   struct external_sun4_dynamic dyninfo;
80   unsigned long dynver;
81   struct external_sun4_dynamic_link linkinfo;
82
83   if (obj_aout_dynamic_info (abfd) != (PTR) NULL)
84     return true;
85
86   info = ((struct sunos_dynamic_info *)
87           bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info)));
88   if (!info)
89     {
90       bfd_error = no_memory;
91       return false;
92     }
93   info->valid = false;
94   info->dynsym = NULL;
95   info->dynstr = NULL;
96   info->dynrel = NULL;
97   obj_aout_dynamic_info (abfd) = (PTR) info;
98
99   /* We look for the __DYNAMIC symbol to locate the dynamic linking
100      information.  It should be the first symbol if it is defined.  If
101      we can't find it, don't sweat it.  */
102   if ((abfd->flags & DYNAMIC) == 0
103       || bfd_get_symcount (abfd) <= 0
104       || bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0
105       || (bfd_read ((PTR) &dynsym, 1, EXTERNAL_NLIST_SIZE, abfd)
106           != EXTERNAL_NLIST_SIZE)
107       || ((dynsym.e_type[0] & N_TYPE) != N_DATA
108           && (dynsym.e_type[0] & N_TYPE) != N_TEXT)
109       || bfd_seek (abfd,
110                    obj_str_filepos (abfd) + GET_WORD (abfd, dynsym.e_strx),
111                    SEEK_SET) != 0
112       || bfd_read ((PTR) buf, 1, sizeof buf, abfd) != sizeof buf
113       || buf[sizeof buf - 1] != '\0'
114       || strcmp (buf, "__DYNAMIC") != 0)
115     return true;
116
117   if ((dynsym.e_type[0] & N_TYPE) == N_DATA)
118     dynsec = obj_datasec (abfd);
119   else
120     dynsec = obj_textsec (abfd);
121   if (! bfd_get_section_contents (abfd, dynsec, (PTR) &dyninfo,
122                                   (GET_WORD (abfd, dynsym.e_value)
123                                    - bfd_get_section_vma (abfd, dynsec)),
124                                   sizeof dyninfo))
125     return true;
126
127   dynver = GET_WORD (abfd, dyninfo.ld_version);
128   if (dynver != 2 && dynver != 3)
129     return true;
130
131   dynoff = GET_WORD (abfd, dyninfo.ld);
132
133   /* dynoff is a virtual address.  It is probably always in the .data
134      section, but this code should work even if it moves.  */
135   if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd)))
136     dynsec = obj_textsec (abfd);
137   else
138     dynsec = obj_datasec (abfd);
139   dynoff -= bfd_get_section_vma (abfd, dynsec);
140   if (dynoff < 0 || dynoff > bfd_section_size (abfd, dynsec))
141     return true;
142
143   /* This executable appears to be dynamically linked in a way that we
144      can understand.  */
145   if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff,
146                                   (bfd_size_type) sizeof linkinfo))
147     return true;
148
149   /* Swap in the dynamic link information.  */
150   info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded);
151   info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need);
152   info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules);
153   info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got);
154   info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt);
155   info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel);
156   info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash);
157   info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab);
158   info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash);
159   info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets);
160   info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols);
161   info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size);
162   info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text);
163   info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz);
164
165   /* The only way to get the size of the symbol information appears to
166      be to determine the distance between it and the string table.  */
167   info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab)
168                         / EXTERNAL_NLIST_SIZE);
169   BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE
170               == info->dyninfo.ld_symbols - info->dyninfo.ld_stab);
171
172   /* Similarly, the relocs end at the hash table.  */
173   info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel)
174                         / obj_reloc_entry_size (abfd));
175   BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd)
176               == info->dyninfo.ld_hash - info->dyninfo.ld_rel);
177
178   info->valid = true;
179
180   return true;
181 }
182
183 /* Read in the dynamic symbols.  */
184
185 static bfd_size_type
186 MY(read_dynamic_symbols) (abfd, syms, strs, strsize)
187      bfd *abfd;
188      struct external_nlist **syms;
189      char **strs;
190      bfd_size_type *strsize;
191 {
192   struct sunos_dynamic_info *info;
193
194   if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
195     {
196       if (! sunos_read_dynamic_info (abfd))
197           return (bfd_size_type) -1;
198     }
199
200   info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
201   if (! info->valid || info->dynsym_count == 0)
202     return 0;
203
204   if (info->dynsym == (struct external_nlist *) NULL)
205     {
206       info->dynsym = ((struct external_nlist *)
207                       bfd_alloc (abfd,
208                                  (info->dynsym_count
209                                   * EXTERNAL_NLIST_SIZE)));
210       info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size);
211       if (!info->dynsym || !info->dynstr)
212         {
213           bfd_error = no_memory;
214           return 0;
215         }
216       if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0
217           || (bfd_read ((PTR) info->dynsym, info->dynsym_count,
218                         EXTERNAL_NLIST_SIZE, abfd)
219               != info->dynsym_count * EXTERNAL_NLIST_SIZE)
220           || bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0
221           || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size,
222                         abfd)
223               != info->dyninfo.ld_symb_size))
224         return (bfd_size_type) -1;
225     }
226
227   *syms = info->dynsym;
228   *strs = info->dynstr;
229   *strsize = info->dyninfo.ld_symb_size;
230
231 #ifdef CHECK_DYNAMIC_HASH
232   /* Check my understanding of the dynamic hash table by making sure
233      that each symbol can be located in the hash table.  */
234   {
235     bfd_size_type table_size;
236     bfd_byte *table;
237     bfd_size_type i;
238
239     if (info->dyninfo.ld_buckets > info->dynsym_count)
240       abort ();
241     table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
242     table = (bfd_byte *) alloca (table_size);
243     if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0
244         || bfd_read ((PTR) table, 1, table_size, abfd) != table_size)
245       abort ();
246     for (i = 0; i < info->dynsym_count; i++)
247       {
248         unsigned char *name;
249         unsigned long hash;
250
251         name = ((unsigned char *) info->dynstr
252                 + GET_WORD (abfd, info->dynsym[i].e_strx));
253         hash = 0;
254         while (*name != '\0')
255           hash = (hash << 1) + *name++;
256         hash &= 0x7fffffff;
257         hash %= info->dyninfo.ld_buckets;
258         while (GET_WORD (abfd, table + 8 * hash) != i)
259           {
260             hash = GET_WORD (abfd, table + 8 * hash + 4);
261             if (hash == 0 || hash >= table_size / 8)
262               abort ();
263           }
264       }
265   }
266 #endif /* CHECK_DYNAMIC_HASH */
267
268   return info->dynsym_count;
269 }
270
271 /* Read in the dynamic relocs for a section.  */
272
273 static bfd_size_type
274 MY(read_dynamic_relocs) (abfd, relocs)
275      bfd *abfd;
276      PTR *relocs;
277 {
278   struct sunos_dynamic_info *info;
279
280   if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
281     {
282       if (! sunos_read_dynamic_info (abfd))
283           return (bfd_size_type) -1;
284     }
285
286   info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd);
287   if (! info->valid || info->dynrel_count == 0)
288     return 0;
289
290   if (info->dynrel == NULL)
291     {
292       info->dynrel = (PTR) bfd_alloc (abfd,
293                                       (info->dynrel_count
294                                        * obj_reloc_entry_size (abfd)));
295       if (!info->dynrel)
296         {
297           bfd_error = no_memory;
298           return (bfd_size_type) -1;
299         }
300       if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0
301           || (bfd_read ((PTR) info->dynrel, info->dynrel_count,
302                         obj_reloc_entry_size (abfd), abfd)
303               != info->dynrel_count * obj_reloc_entry_size (abfd)))
304         return (bfd_size_type) -1;
305     }
306
307   *relocs = info->dynrel;
308
309   return info->dynrel_count;
310 }