1164190Sjkoshy/*-
2164190Sjkoshy * Copyright (c) 2006 Joseph Koshy
3164190Sjkoshy * All rights reserved.
4164190Sjkoshy *
5164190Sjkoshy * Redistribution and use in source and binary forms, with or without
6164190Sjkoshy * modification, are permitted provided that the following conditions
7164190Sjkoshy * are met:
8164190Sjkoshy * 1. Redistributions of source code must retain the above copyright
9164190Sjkoshy *    notice, this list of conditions and the following disclaimer.
10164190Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
11164190Sjkoshy *    notice, this list of conditions and the following disclaimer in the
12164190Sjkoshy *    documentation and/or other materials provided with the distribution.
13164190Sjkoshy *
14164190Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164190Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164190Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164190Sjkoshy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164190Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164190Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164190Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164190Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164190Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164190Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164190Sjkoshy * SUCH DAMAGE.
25164190Sjkoshy */
26164190Sjkoshy
27164190Sjkoshy#include <sys/cdefs.h>
28164190Sjkoshy__FBSDID("$FreeBSD$");
29164190Sjkoshy
30164190Sjkoshy#include <sys/param.h>
31164190Sjkoshy
32164190Sjkoshy#include <assert.h>
33164190Sjkoshy#include <gelf.h>
34164190Sjkoshy
35164190Sjkoshy#include "_libelf.h"
36164190Sjkoshy
37164190Sjkoshy/*
38164190Sjkoshy * Convert an ELF section#,offset pair to a string pointer.
39164190Sjkoshy */
40164190Sjkoshy
41164190Sjkoshychar *
42164190Sjkoshyelf_strptr(Elf *e, size_t scndx, size_t offset)
43164190Sjkoshy{
44164190Sjkoshy	Elf_Scn *s;
45164190Sjkoshy	Elf_Data *d;
46164190Sjkoshy	size_t alignment, count;
47164190Sjkoshy	GElf_Shdr shdr;
48164190Sjkoshy
49164190Sjkoshy	if (e == NULL || e->e_kind != ELF_K_ELF) {
50164190Sjkoshy		LIBELF_SET_ERROR(ARGUMENT, 0);
51164190Sjkoshy		return (NULL);
52164190Sjkoshy	}
53164190Sjkoshy
54164190Sjkoshy	if ((s = elf_getscn(e, scndx)) == NULL ||
55164190Sjkoshy	    gelf_getshdr(s, &shdr) == NULL)
56164190Sjkoshy		return (NULL);
57164190Sjkoshy
58179241Sjb	if (/*shdr.sh_type != SHT_STRTAB || */
59164190Sjkoshy	    offset >= shdr.sh_size) {
60164190Sjkoshy		LIBELF_SET_ERROR(ARGUMENT, 0);
61164190Sjkoshy		return (NULL);
62164190Sjkoshy	}
63164190Sjkoshy
64164190Sjkoshy	d = NULL;
65164190Sjkoshy	if (e->e_flags & ELF_F_LAYOUT) {
66164190Sjkoshy
67164190Sjkoshy		/*
68164190Sjkoshy		 * The application is taking responsibility for the
69164190Sjkoshy		 * ELF object's layout, so we can directly translate
70164190Sjkoshy		 * an offset to a `char *' address using the `d_off'
71164190Sjkoshy		 * members of Elf_Data descriptors.
72164190Sjkoshy		 */
73164190Sjkoshy		while ((d = elf_getdata(s, d)) != NULL) {
74164190Sjkoshy
75164190Sjkoshy			if (d->d_buf == 0 || d->d_size == 0)
76164190Sjkoshy				continue;
77164190Sjkoshy
78164190Sjkoshy			if (d->d_type != ELF_T_BYTE) {
79164190Sjkoshy				LIBELF_SET_ERROR(DATA, 0);
80164190Sjkoshy				return (NULL);
81164190Sjkoshy			}
82164190Sjkoshy
83164190Sjkoshy			if (offset >= d->d_off &&
84164190Sjkoshy			    offset < d->d_off + d->d_size)
85164190Sjkoshy				return ((char *) d->d_buf + offset - d->d_off);
86164190Sjkoshy		}
87164190Sjkoshy	} else {
88164190Sjkoshy		/*
89164190Sjkoshy		 * Otherwise, the `d_off' members are not useable and
90164190Sjkoshy		 * we need to compute offsets ourselves, taking into
91164190Sjkoshy		 * account 'holes' in coverage of the section introduced
92164190Sjkoshy		 * by alignment requirements.
93164190Sjkoshy		 */
94164190Sjkoshy		count = (size_t) 0;	/* cumulative count of bytes seen */
95164190Sjkoshy		while ((d = elf_getdata(s, d)) != NULL && count <= offset) {
96164190Sjkoshy
97164190Sjkoshy			if (d->d_buf == NULL || d->d_size == 0)
98164190Sjkoshy				continue;
99164190Sjkoshy
100164190Sjkoshy			if (d->d_type != ELF_T_BYTE) {
101164190Sjkoshy				LIBELF_SET_ERROR(DATA, 0);
102164190Sjkoshy				return (NULL);
103164190Sjkoshy			}
104164190Sjkoshy
105164190Sjkoshy			if ((alignment = d->d_align) > 1) {
106164190Sjkoshy				if ((alignment & (alignment - 1)) != 0) {
107164190Sjkoshy					LIBELF_SET_ERROR(DATA, 0);
108164190Sjkoshy					return (NULL);
109164190Sjkoshy				}
110164190Sjkoshy				count = roundup2(count, alignment);
111164190Sjkoshy			}
112164190Sjkoshy
113164190Sjkoshy			if (offset < count) {
114164190Sjkoshy				/* offset starts in the 'hole' */
115164190Sjkoshy				LIBELF_SET_ERROR(ARGUMENT, 0);
116164190Sjkoshy				return (NULL);
117164190Sjkoshy			}
118164190Sjkoshy
119164190Sjkoshy			if (offset < count + d->d_size) {
120164190Sjkoshy				if (d->d_buf != NULL)
121164190Sjkoshy					return ((char *) d->d_buf +
122164190Sjkoshy					    offset - count);
123164190Sjkoshy				LIBELF_SET_ERROR(DATA, 0);
124164190Sjkoshy				return (NULL);
125164190Sjkoshy			}
126164190Sjkoshy
127164190Sjkoshy			count += d->d_size;
128164190Sjkoshy		}
129164190Sjkoshy	}
130164190Sjkoshy
131164190Sjkoshy	LIBELF_SET_ERROR(ARGUMENT, 0);
132164190Sjkoshy	return (NULL);
133164190Sjkoshy}
134