1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/* Return string pointer from string section.
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2008, 2009 Red Hat, Inc.
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   This file is part of Red Hat elfutils.
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Red Hat elfutils is free software; you can redistribute it and/or modify
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   it under the terms of the GNU General Public License as published by the
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Free Software Foundation; version 2 of the License.
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Red Hat elfutils is distributed in the hope that it will be useful, but
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   WITHOUT ANY WARRANTY; without even the implied warranty of
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   General Public License for more details.
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   You should have received a copy of the GNU General Public License along
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   with Red Hat elfutils; if not, write to the Free Software Foundation,
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   In addition, as a special exception, Red Hat, Inc. gives You the
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   additional right to link the code of Red Hat elfutils with code licensed
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   under any Open Source Initiative certified open source license
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   (http://www.opensource.org/licenses/index.php) which requires the
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   distribution of source code with any binary distribution and to
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   distribute linked combinations of the two.  Non-GPL Code permitted under
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   this exception must only link to the code of Red Hat elfutils through
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   those well defined interfaces identified in the file named EXCEPTION
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   found in the source code files (the "Approved Interfaces").  The files
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   of Non-GPL Code may instantiate templates or use macros or inline
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   functions from the Approved Interfaces without causing the resulting
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   work to be covered by the GNU General Public License.  Only Red Hat,
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Inc. may make changes or additions to the list of Approved Interfaces.
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Red Hat's grant of this exception is conditioned upon your not adding
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   any new exceptions.  If you wish to add a new Approved Interface or
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   exception, please contact Red Hat.  You must obey the GNU General Public
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   License in all respects for all of the Red Hat elfutils code and other
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   code used in conjunction with Red Hat elfutils except the Non-GPL Code
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   covered by this exception.  If you modify this file, you may extend this
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   exception to your version of the file, but you are not obligated to do
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   so.  If you do not wish to provide this exception without modification,
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   you must delete this exception statement from your version and license
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   this file solely under the GPL without exception.
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Red Hat elfutils is an included package of the Open Invention Network.
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   An included package of the Open Invention Network is a package for which
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Open Invention Network licensees cross-license their patents.  No patent
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   license is granted, either expressly or impliedly, by designation as an
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   included package.  Should you wish to participate in the Open Invention
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   Network licensing program, please visit www.openinventionnetwork.com
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver   <http://www.openinventionnetwork.com>.  */
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#ifdef HAVE_CONFIG_H
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# include <config.h>
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#endif
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#include <libelf.h>
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#include <stddef.h>
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#include "libelfP.h"
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverchar *
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverelf_strptr (elf, idx, offset)
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     Elf *elf;
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     size_t idx;
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     size_t offset;
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver{
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  if (elf == NULL)
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return NULL;
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  if (elf->kind != ELF_K_ELF)
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    {
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      __libelf_seterrno (ELF_E_INVALID_HANDLE);
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return NULL;
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  rwlock_rdlock (elf->lock);
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  char *result = NULL;
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Elf_Scn *strscn;
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  /* Find the section in the list.  */
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Elf_ScnList *runp = (elf->class == ELFCLASS32
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		       || (offsetof (struct Elf, state.elf32.scns)
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			   == offsetof (struct Elf, state.elf64.scns))
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		       ? &elf->state.elf32.scns : &elf->state.elf64.scns);
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  while (1)
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    {
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if (idx < runp->max)
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	{
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	  if (idx < runp->cnt)
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    strscn = &runp->data[idx];
92	  else
93	    {
94	      __libelf_seterrno (ELF_E_INVALID_INDEX);
95	      goto out;
96	    }
97	  break;
98	}
99
100      idx -= runp->max;
101
102      runp = runp->next;
103      if (runp == NULL)
104	{
105	  __libelf_seterrno (ELF_E_INVALID_INDEX);
106	  goto out;
107	}
108    }
109
110  if (elf->class == ELFCLASS32)
111    {
112      if (unlikely (strscn->shdr.e32->sh_type != SHT_STRTAB))
113	{
114	  /* This is no string section.  */
115	  __libelf_seterrno (ELF_E_INVALID_SECTION);
116	  goto out;
117	}
118
119      if (unlikely (offset >= strscn->shdr.e32->sh_size))
120	{
121	  /* The given offset is too big, it is beyond this section.  */
122	  __libelf_seterrno (ELF_E_OFFSET_RANGE);
123	  goto out;
124	}
125    }
126  else
127    {
128      if (unlikely (strscn->shdr.e64->sh_type != SHT_STRTAB))
129	{
130	  /* This is no string section.  */
131	  __libelf_seterrno (ELF_E_INVALID_SECTION);
132	  goto out;
133	}
134
135      if (unlikely (offset >= strscn->shdr.e64->sh_size))
136	{
137	  /* The given offset is too big, it is beyond this section.  */
138	  __libelf_seterrno (ELF_E_OFFSET_RANGE);
139	  goto out;
140	}
141    }
142
143  if (strscn->rawdata_base == NULL && ! strscn->data_read)
144    {
145      rwlock_unlock (elf->lock);
146      rwlock_wrlock (elf->lock);
147      if (strscn->rawdata_base == NULL && ! strscn->data_read
148	/* Read the section data.  */
149	  && __libelf_set_rawdata_wrlock (strscn) != 0)
150	goto out;
151    }
152
153  if (likely (strscn->rawdata_base != NULL))
154    // XXX Is this correct if a file is read and then new data is added
155    // XXX to the string section?  Likely needs to check offset against
156    // XXX size of rawdata_base buffer and then iterate over rest of the
157    // XXX list.
158    result = &strscn->rawdata_base[offset];
159  else
160    {
161      /* This is a file which is currently created.  Use the list of
162	 data blocks.  */
163      struct Elf_Data_List *dl = &strscn->data_list;
164      while (dl != NULL)
165	{
166	  if (offset >= (size_t) dl->data.d.d_off
167	      && offset < dl->data.d.d_off + dl->data.d.d_size)
168	    {
169	      result = (char *) dl->data.d.d_buf + (offset - dl->data.d.d_off);
170	      break;
171	    }
172
173	  dl = dl->next;
174	}
175    }
176
177 out:
178  rwlock_unlock (elf->lock);
179
180  return result;
181}
182INTDEF(elf_strptr)
183