~ubuntu-branches/debian/lenny/elfutils/lenny

« back to all changes in this revision

Viewing changes to libelf/elf_getdata.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2006-08-27 15:48:23 UTC
  • Revision ID: james.westby@ubuntu.com-20060827154823-mjwd7ydlbxgwqn4u
Tags: upstream-0.123
ImportĀ upstreamĀ versionĀ 0.123

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Return the next data element from the section after possibly converting it.
 
2
   Copyright (C) 1998-2005, 2006 Red Hat, Inc.
 
3
   This file is part of Red Hat elfutils.
 
4
   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
 
5
 
 
6
   Red Hat elfutils is free software; you can redistribute it and/or modify
 
7
   it under the terms of the GNU General Public License as published by the
 
8
   Free Software Foundation; version 2 of the License.
 
9
 
 
10
   Red Hat elfutils is distributed in the hope that it will be useful, but
 
11
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
   General Public License for more details.
 
14
 
 
15
   You should have received a copy of the GNU General Public License along
 
16
   with Red Hat elfutils; if not, write to the Free Software Foundation,
 
17
   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
 
18
 
 
19
   In addition, as a special exception, Red Hat, Inc. gives You the
 
20
   additional right to link the code of Red Hat elfutils with code licensed
 
21
   under any Open Source Initiative certified open source license
 
22
   (http://www.opensource.org/licenses/index.php) which requires the
 
23
   distribution of source code with any binary distribution and to
 
24
   distribute linked combinations of the two.  Non-GPL Code permitted under
 
25
   this exception must only link to the code of Red Hat elfutils through
 
26
   those well defined interfaces identified in the file named EXCEPTION
 
27
   found in the source code files (the "Approved Interfaces").  The files
 
28
   of Non-GPL Code may instantiate templates or use macros or inline
 
29
   functions from the Approved Interfaces without causing the resulting
 
30
   work to be covered by the GNU General Public License.  Only Red Hat,
 
31
   Inc. may make changes or additions to the list of Approved Interfaces.
 
32
   Red Hat's grant of this exception is conditioned upon your not adding
 
33
   any new exceptions.  If you wish to add a new Approved Interface or
 
34
   exception, please contact Red Hat.  You must obey the GNU General Public
 
35
   License in all respects for all of the Red Hat elfutils code and other
 
36
   code used in conjunction with Red Hat elfutils except the Non-GPL Code
 
37
   covered by this exception.  If you modify this file, you may extend this
 
38
   exception to your version of the file, but you are not obligated to do
 
39
   so.  If you do not wish to provide this exception without modification,
 
40
   you must delete this exception statement from your version and license
 
41
   this file solely under the GPL without exception.
 
42
 
 
43
   Red Hat elfutils is an included package of the Open Invention Network.
 
44
   An included package of the Open Invention Network is a package for which
 
45
   Open Invention Network licensees cross-license their patents.  No patent
 
46
   license is granted, either expressly or impliedly, by designation as an
 
47
   included package.  Should you wish to participate in the Open Invention
 
48
   Network licensing program, please visit www.openinventionnetwork.com
 
49
   <http://www.openinventionnetwork.com>.  */
 
50
 
 
51
#ifdef HAVE_CONFIG_H
 
52
# include <config.h>
 
53
#endif
 
54
 
 
55
#include <errno.h>
 
56
#include <stddef.h>
 
57
#include <string.h>
 
58
#include <unistd.h>
 
59
 
 
60
#include "libelfP.h"
 
61
#include <system.h>
 
62
#include "common.h"
 
63
#include "elf-knowledge.h"
 
64
 
 
65
 
 
66
#if _STRING_ARCH_unaligned
 
67
# define ALLOW_ALIGNED  1
 
68
#else
 
69
# define ALLOW_ALIGNED  0
 
70
#endif
 
71
 
 
72
 
 
73
#define TYPEIDX(Sh_Type) \
 
74
  (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM                                   \
 
75
   ? Sh_Type                                                                  \
 
76
   : (Sh_Type >= SHT_GNU_HASH && Sh_Type <= SHT_HISUNW                        \
 
77
      ? SHT_NUM + Sh_Type - SHT_GNU_HASH                                      \
 
78
      : 0))
 
79
 
 
80
static const struct
 
81
{
 
82
  Elf_Type type;
 
83
  size_t size;
 
84
#if ALLOW_ALIGNED
 
85
# define AL(val)
 
86
#else
 
87
  size_t align;
 
88
# define AL(val), val
 
89
#endif
 
90
} shtype_map[EV_NUM - 1][ELFCLASSNUM - 1][TYPEIDX (SHT_HISUNW) + 1] =
 
91
{
 
92
  [EV_CURRENT - 1] =
 
93
  {
 
94
    [ELFCLASS32 - 1] =
 
95
    {
 
96
      /* Associate section types with libelf types, their sizes and
 
97
         alignment.  SHT_GNU_verdef is special since the section does
 
98
         not contain entries of only one size.  */
 
99
#define DEFINE(Bits) \
 
100
      [SHT_SYMTAB] = { ELF_T_SYM, sizeof (ElfW2(Bits,Sym))                    \
 
101
                       AL (__alignof__ (ElfW2(Bits,Sym))) },                  \
 
102
      [SHT_RELA] = { ELF_T_RELA, sizeof (ElfW2(Bits,Rela))                    \
 
103
                       AL (__alignof__ (ElfW2(Bits,Rela))) },                 \
 
104
      [SHT_HASH] = { ELF_T_WORD, sizeof (ElfW2(Bits,Word))                    \
 
105
                       AL (__alignof__ (ElfW2(Bits,Word))) },                 \
 
106
      [SHT_DYNAMIC] = { ELF_T_DYN, sizeof (ElfW2(Bits,Dyn))                   \
 
107
                       AL (__alignof__ (ElfW2(Bits,Dyn))) },                  \
 
108
      [SHT_REL] = { ELF_T_REL, sizeof (ElfW2(Bits,Rel))                       \
 
109
                       AL (__alignof__ (ElfW2(Bits,Rel))) },                  \
 
110
      [SHT_DYNSYM] = { ELF_T_SYM, sizeof (ElfW2(Bits,Sym))                    \
 
111
                       AL (__alignof__ (ElfW2(Bits,Sym))) },                  \
 
112
      [SHT_INIT_ARRAY] = { ELF_T_ADDR, sizeof (ElfW2(Bits,Addr))              \
 
113
                           AL (__alignof__ (ElfW2(Bits,Addr))) },             \
 
114
      [SHT_FINI_ARRAY] = { ELF_T_ADDR, sizeof (ElfW2(Bits,Addr))              \
 
115
                           AL (__alignof__ (ElfW2(Bits,Addr))) },             \
 
116
      [SHT_PREINIT_ARRAY] = { ELF_T_ADDR, sizeof (ElfW2(Bits,Addr))           \
 
117
                              AL (__alignof__ (ElfW2(Bits,Addr))) },          \
 
118
      [SHT_GROUP] = { ELF_T_WORD, sizeof (Elf32_Word)                         \
 
119
                      AL (__alignof__ (Elf32_Word)) },                        \
 
120
      [SHT_SYMTAB_SHNDX] = { ELF_T_WORD, sizeof (Elf32_Word)                  \
 
121
                             AL (__alignof__ (Elf32_Word)) },                 \
 
122
      [TYPEIDX (SHT_GNU_verdef)] = { ELF_T_VDEF, 1 AL (1) },                  \
 
123
      [TYPEIDX (SHT_GNU_verneed)] = { ELF_T_VNEED,                            \
 
124
                                      sizeof (ElfW2(Bits,Verneed))            \
 
125
                                      AL (__alignof__ (ElfW2(Bits,Verneed)))},\
 
126
      [TYPEIDX (SHT_GNU_versym)] = { ELF_T_HALF, sizeof (ElfW2(Bits,Versym))  \
 
127
                                     AL (__alignof__ (ElfW2(Bits,Versym))) }, \
 
128
      [TYPEIDX (SHT_SUNW_syminfo)] = { ELF_T_SYMINFO,                         \
 
129
                                       sizeof (ElfW2(Bits,Syminfo))           \
 
130
                                       AL(__alignof__ (ElfW2(Bits,Syminfo)))},\
 
131
      [TYPEIDX (SHT_SUNW_move)] = { ELF_T_MOVE, sizeof (ElfW2(Bits,Move))     \
 
132
                                    AL (__alignof__ (ElfW2(Bits,Move))) },    \
 
133
      [TYPEIDX (SHT_GNU_LIBLIST)] = { ELF_T_LIB, sizeof (ElfW2(Bits,Lib))     \
 
134
                                      AL (__alignof__ (ElfW2(Bits,Lib))) }
 
135
      DEFINE (32),
 
136
      [TYPEIDX (SHT_GNU_HASH)] = { ELF_T_WORD, sizeof (Elf32_Word)
 
137
                                   AL (__alignof__ (Elf32_Word)) }
 
138
    },
 
139
    [ELFCLASS64 - 1] =
 
140
    {
 
141
      DEFINE (64),
 
142
      [TYPEIDX (SHT_GNU_HASH)] = { ELF_T_GNUHASH, 1
 
143
                                   AL (__alignof__ (Elf64_Xword)) }
 
144
    }
 
145
  }
 
146
};
 
147
 
 
148
 
 
149
/* Convert the data in the current section.  */
 
150
static void
 
151
convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass,
 
152
              int data, size_t size, size_t type)
 
153
{
 
154
#if ALLOW_ALIGNED
 
155
  /* No need to compute the alignment requirement of the host.  */
 
156
  const size_t align = 1;
 
157
#else
 
158
# if EV_NUM != 2
 
159
  size_t align = shtype_map[version - 1][eclass - 1][type].align;
 
160
# else
 
161
  size_t align = shtype_map[0][eclass - 1][type].align;
 
162
# endif
 
163
#endif
 
164
 
 
165
  if (data == MY_ELFDATA)
 
166
    {
 
167
      if (ALLOW_ALIGNED
 
168
          || (((size_t) ((char *) scn->rawdata_base)) & (align - 1)) == 0)
 
169
        /* No need to copy, we can use the raw data.  */
 
170
        scn->data_base = scn->rawdata_base;
 
171
      else
 
172
        {
 
173
          scn->data_base = (char *) malloc (size);
 
174
          if (scn->data_base == NULL)
 
175
            {
 
176
              __libelf_seterrno (ELF_E_NOMEM);
 
177
              return;
 
178
            }
 
179
 
 
180
          /* The copy will be appropriately aligned for direct access.  */
 
181
          memcpy (scn->data_base, scn->rawdata_base, size);
 
182
        }
 
183
    }
 
184
  else
 
185
    {
 
186
      xfct_t fp;
 
187
 
 
188
      scn->data_base = (char *) malloc (size);
 
189
      if (scn->data_base == NULL)
 
190
        {
 
191
          __libelf_seterrno (ELF_E_NOMEM);
 
192
          return;
 
193
        }
 
194
 
 
195
      /* Get the conversion function.  */
 
196
#if EV_NUM != 2
 
197
      fp = __elf_xfctstom[version - 1][__libelf_version - 1][eclass - 1][type];
 
198
#else
 
199
      fp = __elf_xfctstom[0][0][eclass - 1][type];
 
200
#endif
 
201
 
 
202
      fp (scn->data_base, scn->rawdata_base, size, 0);
 
203
    }
 
204
 
 
205
  scn->data_list.data.d.d_buf = scn->data_base;
 
206
  scn->data_list.data.d.d_size = size;
 
207
  scn->data_list.data.d.d_type = type;
 
208
  scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
 
209
  scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
 
210
  scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
 
211
 
 
212
  scn->data_list.data.s = scn;
 
213
}
 
214
 
 
215
 
 
216
/* Store the information for the raw data in the `rawdata' element.  */
 
217
int
 
218
internal_function
 
219
__libelf_set_rawdata (Elf_Scn *scn)
 
220
{
 
221
  size_t offset;
 
222
  size_t size;
 
223
  size_t align;
 
224
  int type;
 
225
  Elf *elf = scn->elf;
 
226
 
 
227
  if (elf->class == ELFCLASS32)
 
228
    {
 
229
      Elf32_Shdr *shdr = scn->shdr.e32 ?: INTUSE(elf32_getshdr) (scn);
 
230
 
 
231
      if (shdr == NULL)
 
232
        /* Something went terribly wrong.  */
 
233
        return 1;
 
234
 
 
235
      offset = shdr->sh_offset;
 
236
      size = shdr->sh_size;
 
237
      type = shdr->sh_type;
 
238
      align = shdr->sh_addralign;
 
239
    }
 
240
  else
 
241
    {
 
242
      Elf64_Shdr *shdr = scn->shdr.e64 ?: INTUSE(elf64_getshdr) (scn);
 
243
 
 
244
      if (shdr == NULL)
 
245
        /* Something went terribly wrong.  */
 
246
        return 1;
 
247
 
 
248
      offset = shdr->sh_offset;
 
249
      size = shdr->sh_size;
 
250
      type = shdr->sh_type;
 
251
      align = shdr->sh_addralign;
 
252
    }
 
253
 
 
254
  /* If the section has no data (for whatever reason), leave the `d_buf'
 
255
     pointer NULL.  */
 
256
  if (size != 0 && type != SHT_NOBITS)
 
257
    {
 
258
      /* First a test whether the section is valid at all.  */
 
259
      size_t entsize;
 
260
 
 
261
      if (type == SHT_HASH)
 
262
        {
 
263
          GElf_Ehdr ehdr_mem;
 
264
 
 
265
          entsize = SH_ENTSIZE_HASH (INTUSE(gelf_getehdr) (elf, &ehdr_mem));
 
266
        }
 
267
      else
 
268
        {
 
269
#if EV_NUM != 2
 
270
          entsize = shtype_map[__libelf_version - 1][elf->class - 1][TYPEIDX (type)].size;
 
271
#else
 
272
          entsize = shtype_map[0][elf->class - 1][TYPEIDX (type)].size;
 
273
#endif
 
274
        }
 
275
 
 
276
      /* We assume it is an array of bytes if it is none of the structured
 
277
         sections we know of.  */
 
278
      if (entsize == 0)
 
279
        entsize = 1;
 
280
 
 
281
      if (unlikely (size % entsize != 0))
 
282
        {
 
283
          __libelf_seterrno (ELF_E_INVALID_DATA);
 
284
          return 1;
 
285
        }
 
286
 
 
287
      /* We can use the mapped or loaded data if available.  */
 
288
      if (elf->map_address != NULL)
 
289
        {
 
290
          /* First see whether the information in the section header is
 
291
             valid and it does not ask for too much.  */
 
292
          if (unlikely (offset + size > elf->maximum_size))
 
293
            {
 
294
              /* Something is wrong.  */
 
295
              __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
 
296
              return 1;
 
297
            }
 
298
 
 
299
          scn->rawdata_base = scn->rawdata.d.d_buf
 
300
            = (char *) elf->map_address + elf->start_offset + offset;
 
301
        }
 
302
      else if (likely (elf->fildes != -1))
 
303
        {
 
304
          /* We have to read the data from the file.  Allocate the needed
 
305
             memory.  */
 
306
          scn->rawdata_base = scn->rawdata.d.d_buf
 
307
            = (char *) malloc (size);
 
308
          if (scn->rawdata.d.d_buf == NULL)
 
309
            {
 
310
              __libelf_seterrno (ELF_E_NOMEM);
 
311
              return 1;
 
312
            }
 
313
 
 
314
          ssize_t n = pread_retry (elf->fildes, scn->rawdata.d.d_buf, size,
 
315
                                   elf->start_offset + offset);
 
316
          if (unlikely ((size_t) n != size))
 
317
            {
 
318
              /* Cannot read the data.  */
 
319
              free (scn->rawdata.d.d_buf);
 
320
              scn->rawdata_base = scn->rawdata.d.d_buf = NULL;
 
321
              __libelf_seterrno (ELF_E_READ_ERROR);
 
322
              return 1;
 
323
            }
 
324
        }
 
325
      else
 
326
        {
 
327
          /* The file descriptor is already closed, we cannot get the data
 
328
             anymore.  */
 
329
          __libelf_seterrno (ELF_E_FD_DISABLED);
 
330
          return 1;
 
331
        }
 
332
    }
 
333
 
 
334
  scn->rawdata.d.d_size = size;
 
335
  /* Some broken ELF ABI for 64-bit machines use the wrong hash table
 
336
     entry size.  See elf-knowledge.h for more information.  */
 
337
  if (type == SHT_HASH && elf->class == ELFCLASS64)
 
338
    {
 
339
      GElf_Ehdr ehdr_mem;
 
340
 
 
341
      scn->rawdata.d.d_type
 
342
        = (SH_ENTSIZE_HASH (INTUSE(gelf_getehdr) (elf, &ehdr_mem)) == 4
 
343
           ? ELF_T_WORD : ELF_T_XWORD);
 
344
    }
 
345
  else
 
346
    {
 
347
#if EV_NUM != 2
 
348
      scn->rawdata.d.d_type =
 
349
        shtype_map[__libelf_version - 1][elf->class - 1][TYPEIDX (type)].type;
 
350
#else
 
351
      scn->rawdata.d.d_type =
 
352
        shtype_map[0][elf->class - 1][TYPEIDX (type)].type;
 
353
#endif
 
354
    }
 
355
  scn->rawdata.d.d_off = 0;
 
356
  scn->rawdata.d.d_align = align;
 
357
  if (elf->class == ELFCLASS32
 
358
      || (offsetof (struct Elf, state.elf32.ehdr)
 
359
          == offsetof (struct Elf, state.elf64.ehdr)))
 
360
    scn->rawdata.d.d_version =
 
361
      elf->state.elf32.ehdr->e_ident[EI_VERSION];
 
362
  else
 
363
    scn->rawdata.d.d_version =
 
364
      elf->state.elf64.ehdr->e_ident[EI_VERSION];
 
365
 
 
366
  scn->rawdata.s = scn;
 
367
 
 
368
  scn->data_read = 1;
 
369
 
 
370
  /* We actually read data from the file.  At least we tried.  */
 
371
  scn->flags |= ELF_F_FILEDATA;
 
372
 
 
373
  return 0;
 
374
}
 
375
 
 
376
 
 
377
Elf_Data *
 
378
elf_getdata (scn, data)
 
379
     Elf_Scn *scn;
 
380
     Elf_Data *data;
 
381
{
 
382
  Elf_Data *result = NULL;
 
383
  Elf *elf;
 
384
 
 
385
  if (scn == NULL)
 
386
    return NULL;
 
387
 
 
388
  if (unlikely (scn->elf->kind != ELF_K_ELF))
 
389
    {
 
390
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
 
391
      return NULL;
 
392
    }
 
393
 
 
394
  /* We will need this multiple times later on.  */
 
395
  elf = scn->elf;
 
396
 
 
397
  rwlock_rdlock (elf->lock);
 
398
 
 
399
  /* If `data' is not NULL this means we are not addressing the initial
 
400
     data in the file.  But this also means this data is already read
 
401
     (since otherwise it is not possible to have a valid `data' pointer)
 
402
     and all the data structures are initialized as well.  In this case
 
403
     we can simply walk the list of data records.  */
 
404
  if (data != NULL)
 
405
    {
 
406
      Elf_Data_List *runp;
 
407
 
 
408
      /* It is not possible that if DATA is not NULL the first entry is
 
409
         returned.  But this also means that there must be a first data
 
410
         entry.  */
 
411
      if (scn->data_list_rear == NULL
 
412
          /* The section the reference data is for must match the section
 
413
             parameter.  */
 
414
          || unlikely (((Elf_Data_Scn *) data)->s != scn))
 
415
        {
 
416
          __libelf_seterrno (ELF_E_DATA_MISMATCH);
 
417
          goto out;
 
418
        }
 
419
 
 
420
      /* We start searching with the first entry.  */
 
421
      runp = &scn->data_list;
 
422
 
 
423
      while (1)
 
424
        {
 
425
          /* If `data' does not match any known record punt.  */
 
426
          if (runp == NULL)
 
427
            {
 
428
              __libelf_seterrno (ELF_E_DATA_MISMATCH);
 
429
              goto out;
 
430
            }
 
431
 
 
432
          if (&runp->data.d == data)
 
433
            /* Found the entry.  */
 
434
            break;
 
435
 
 
436
          runp = runp->next;
 
437
        }
 
438
 
 
439
      /* Return the data for the next data record.  */
 
440
      result = runp->next ? &runp->next->data.d : NULL;
 
441
      goto out;
 
442
    }
 
443
 
 
444
  /* If the data for this section was not yet initialized do it now.  */
 
445
  if (scn->data_read == 0)
 
446
    {
 
447
      /* We cannot acquire a write lock while we are holding a read
 
448
         lock.  Therefore give up the read lock and then get the write
 
449
         lock.  But this means that the data could meanwhile be
 
450
         modified, therefore start the tests again.  */
 
451
      rwlock_unlock (elf->lock);
 
452
      rwlock_wrlock (elf->lock);
 
453
 
 
454
      /* Read the data from the file.  There is always a file (or
 
455
         memory region) associated with this descriptor since
 
456
         otherwise the `data_read' flag would be set.  */
 
457
      if (scn->data_read == 0 && __libelf_set_rawdata (scn) != 0)
 
458
        /* Something went wrong.  The error value is already set.  */
 
459
        goto out;
 
460
    }
 
461
 
 
462
  /* At this point we know the raw data is available.  But it might be
 
463
     empty in case the section has size zero (for whatever reason).
 
464
     Now create the converted data in case this is necessary.  */
 
465
  if (scn->data_list_rear == NULL)
 
466
    {
 
467
      if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0)
 
468
        /* Convert according to the version and the type.   */
 
469
        convert_data (scn, __libelf_version, elf->class,
 
470
                      (elf->class == ELFCLASS32
 
471
                       || (offsetof (struct Elf, state.elf32.ehdr)
 
472
                           == offsetof (struct Elf, state.elf64.ehdr))
 
473
                       ? elf->state.elf32.ehdr->e_ident[EI_DATA]
 
474
                       : elf->state.elf64.ehdr->e_ident[EI_DATA]),
 
475
                      scn->rawdata.d.d_size, scn->rawdata.d.d_type);
 
476
      else
 
477
        /* This is an empty or NOBITS section.  There is no buffer but
 
478
           the size information etc is important.  */
 
479
        scn->data_list.data.d = scn->rawdata.d;
 
480
 
 
481
      scn->data_list_rear = &scn->data_list;
 
482
    }
 
483
 
 
484
  /* If no data is present we cannot return any.  */
 
485
  if (scn->data_list_rear != NULL)
 
486
    /* Return the first data element in the list.  */
 
487
    result = &scn->data_list.data.d;
 
488
 
 
489
 out:
 
490
  rwlock_unlock (elf->lock);
 
491
 
 
492
  return result;
 
493
}
 
494
INTDEF(elf_getdata)