1263320Sdim/*-
2263320Sdim * Copyright (c) 2006,2008 Joseph Koshy
3263320Sdim * All rights reserved.
4263320Sdim *
5263320Sdim * Redistribution and use in source and binary forms, with or without
6263320Sdim * modification, are permitted provided that the following conditions
7263320Sdim * are met:
8263320Sdim * 1. Redistributions of source code must retain the above copyright
9263320Sdim *    notice, this list of conditions and the following disclaimer.
10263320Sdim * 2. Redistributions in binary form must reproduce the above copyright
11263320Sdim *    notice, this list of conditions and the following disclaimer in the
12263320Sdim *    documentation and/or other materials provided with the distribution.
13263320Sdim *
14263320Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15263320Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16263320Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17263320Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18263320Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19263320Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20263320Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21263320Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22263320Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23263320Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24263320Sdim * SUCH DAMAGE.
25263320Sdim */
26263320Sdim
27263320Sdim#include <assert.h>
28263320Sdim#include <gelf.h>
29263320Sdim
30263320Sdim#include "_libelf.h"
31263320Sdim
32263320SdimELFTC_VCSID("$Id: gelf_symshndx.c,v 1.2 2020/05/18 06:46:23 jsg Exp $");
33263320Sdim
34263320SdimGElf_Sym *
35263320Sdimgelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst,
36263320Sdim    Elf32_Word *shindex)
37263320Sdim{
38263320Sdim	int ec;
39263320Sdim	Elf *e;
40263320Sdim	size_t msz;
41263320Sdim	Elf_Scn *scn;
42263320Sdim	uint32_t sh_type;
43263320Sdim	struct _Libelf_Data *ld, *lid;
44263320Sdim
45263320Sdim	ld = (struct _Libelf_Data *) d;
46263320Sdim	lid = (struct _Libelf_Data *) id;
47263320Sdim
48263320Sdim	if (gelf_getsym(d, ndx, dst) == 0)
49263320Sdim		return (NULL);
50263320Sdim
51263320Sdim	if (lid == NULL || (scn = lid->d_scn) == NULL ||
52263320Sdim	    (e = scn->s_elf) == NULL || (e != ld->d_scn->s_elf) ||
53263320Sdim	    shindex == NULL) {
54263320Sdim		LIBELF_SET_ERROR(ARGUMENT, 0);
55263320Sdim		return (NULL);
56263320Sdim	}
57263320Sdim
58263320Sdim	ec = e->e_class;
59263320Sdim	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
60263320Sdim
61263320Sdim	if (ec == ELFCLASS32)
62263320Sdim		sh_type = scn->s_shdr.s_shdr32.sh_type;
63263320Sdim	else
64263320Sdim		sh_type = scn->s_shdr.s_shdr64.sh_type;
65263320Sdim
66263320Sdim	if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD ||
67263320Sdim	   id->d_type != ELF_T_WORD) {
68263320Sdim		LIBELF_SET_ERROR(ARGUMENT, 0);
69263320Sdim		return (NULL);
70263320Sdim	}
71263320Sdim
72263320Sdim	if ((msz = _libelf_msize(ELF_T_WORD, ec, e->e_version)) == 0)
73263320Sdim		return (NULL);
74263320Sdim
75263320Sdim	assert(ndx >= 0);
76263320Sdim
77263320Sdim	if (msz * (size_t) ndx >= id->d_size) {
78263320Sdim		LIBELF_SET_ERROR(ARGUMENT, 0);
79263320Sdim		return (NULL);
80263320Sdim	}
81263320Sdim
82263320Sdim	*shindex = ((Elf32_Word *) id->d_buf)[ndx];
83263320Sdim
84263320Sdim	return (dst);
85263320Sdim}
86263320Sdim
87263320Sdimint
88263320Sdimgelf_update_symshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *gs,
89263320Sdim    Elf32_Word xindex)
90263320Sdim{
91263320Sdim	int ec;
92263320Sdim	Elf *e;
93263320Sdim	size_t msz;
94263320Sdim	Elf_Scn *scn;
95263320Sdim	uint32_t sh_type;
96263320Sdim	struct _Libelf_Data *ld, *lid;
97263320Sdim
98263320Sdim	ld = (struct _Libelf_Data *) d;
99263320Sdim	lid = (struct _Libelf_Data *) id;
100263320Sdim
101263320Sdim	if (gelf_update_sym(d, ndx, gs) == 0)
102263320Sdim		return (0);
103263320Sdim
104263320Sdim	if (lid == NULL || (scn = lid->d_scn) == NULL ||
105263320Sdim	    (e = scn->s_elf) == NULL || (e != ld->d_scn->s_elf)) {
106263320Sdim		LIBELF_SET_ERROR(ARGUMENT, 0);
107263320Sdim		return (0);
108263320Sdim	}
109263320Sdim
110263320Sdim	ec = e->e_class;
111263320Sdim	assert(ec == ELFCLASS32 || ec == ELFCLASS64);
112263320Sdim
113263320Sdim	if (ec == ELFCLASS32)
114263320Sdim		sh_type = scn->s_shdr.s_shdr32.sh_type;
115263320Sdim	else
116263320Sdim		sh_type = scn->s_shdr.s_shdr64.sh_type;
117263320Sdim
118263320Sdim	if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD ||
119263320Sdim	    d->d_type != ELF_T_WORD) {
120263320Sdim		LIBELF_SET_ERROR(ARGUMENT, 0);
121263320Sdim		return (0);
122263320Sdim	}
123263320Sdim
124263320Sdim	if ((msz = _libelf_msize(ELF_T_WORD, ec, e->e_version)) == 0)
125263320Sdim		return (0);
126263320Sdim
127263320Sdim	assert(ndx >= 0);
128263320Sdim
129263320Sdim	if (msz * (size_t) ndx >= id->d_size) {
130263320Sdim		LIBELF_SET_ERROR(ARGUMENT, 0);
131263320Sdim		return (0);
132263320Sdim	}
133263320Sdim
134263320Sdim	*(((Elf32_Word *) id->d_buf) + ndx) = xindex;
135263320Sdim
136263320Sdim	return (1);
137263320Sdim}
138263320Sdim