gelf_update_symshndx.c revision 441f72d43a9b550baa779fc82f70816da5f74f0e
1/* Update symbol information and section index in symbol table at the
2   given index.
3   Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, version 2.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software Foundation,
17   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <gelf.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "libelfP.h"
28
29
30int
31gelf_update_symshndx (symdata, shndxdata, ndx, src, srcshndx)
32     Elf_Data *symdata;
33     Elf_Data *shndxdata;
34     int ndx;
35     GElf_Sym *src;
36     Elf32_Word srcshndx;
37{
38  Elf_Data_Scn *symdata_scn = (Elf_Data_Scn *) symdata;
39  Elf_Data_Scn *shndxdata_scn = (Elf_Data_Scn *) shndxdata;
40  Elf_Scn *scn;
41  Elf32_Word *shndx = NULL;
42  int result = 0;
43
44  if (symdata == NULL)
45    return 0;
46
47  if (unlikely (ndx < 0))
48    {
49      __libelf_seterrno (ELF_E_INVALID_INDEX);
50      return 0;
51    }
52
53  if (unlikely (symdata_scn->d.d_type != ELF_T_SYM))
54    {
55      /* The type of the data better should match.  */
56      __libelf_seterrno (ELF_E_DATA_MISMATCH);
57      return 0;
58    }
59
60  scn = symdata_scn->s;
61  /* We simply have to believe the user that the two sections belong to
62     the same ELF file.  */
63  rwlock_wrlock (scn->elf->lock);
64
65  /* The user is not required to pass a data descriptor for an extended
66     section index table.  */
67  if (shndxdata_scn != NULL)
68    {
69      if (unlikely ((ndx + 1) * sizeof (Elf32_Word) > shndxdata_scn->d.d_size))
70	{
71	  __libelf_seterrno (ELF_E_INVALID_INDEX);
72	  goto out;
73	}
74
75      shndx = &((Elf32_Word *) shndxdata_scn->d.d_buf)[ndx];
76    }
77  /* But if s/he does not the extended sectio index must be zero.  */
78  else if (unlikely (srcshndx != 0))
79    {
80      __libelf_seterrno (ELF_E_INVALID_INDEX);
81      goto out;
82    }
83
84  if (scn->elf->class == ELFCLASS32)
85    {
86      Elf32_Sym *sym;
87
88      /* There is the possibility that the values in the input are
89	 too large.  */
90      if (unlikely (src->st_value > 0xffffffffull)
91	  || unlikely (src->st_size > 0xffffffffull))
92	{
93	  __libelf_seterrno (ELF_E_INVALID_DATA);
94	  goto out;
95	}
96
97      /* Check whether we have to resize the data buffer.  */
98      if (unlikely ((ndx + 1) * sizeof (Elf32_Sym) > symdata_scn->d.d_size))
99	{
100	  __libelf_seterrno (ELF_E_INVALID_INDEX);
101	  goto out;
102	}
103
104      sym = &((Elf32_Sym *) symdata_scn->d.d_buf)[ndx];
105
106#define COPY(name) \
107      sym->name = src->name
108      COPY (st_name);
109      COPY (st_value);
110      COPY (st_size);
111      /* Please note that we can simply copy the `st_info' element since
112	 the definitions of ELFxx_ST_BIND and ELFxx_ST_TYPE are the same
113	 for the 64 bit variant.  */
114      COPY (st_info);
115      COPY (st_other);
116      COPY (st_shndx);
117    }
118  else
119    {
120      /* Check whether we have to resize the data buffer.  */
121      if (unlikely ((ndx + 1) * sizeof (Elf64_Sym) > symdata_scn->d.d_size))
122	{
123	  __libelf_seterrno (ELF_E_INVALID_INDEX);
124	  goto out;
125	}
126
127      ((Elf64_Sym *) symdata_scn->d.d_buf)[ndx] = *src;
128    }
129
130  /* Now we can store the section index.  */
131  if (shndx != NULL)
132    *shndx = srcshndx;
133
134  result = 1;
135
136  /* Mark the section as modified.  */
137  scn->flags |= ELF_F_DIRTY;
138
139 out:
140  rwlock_unlock (scn->elf->lock);
141
142  return result;
143}
144