1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1988 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30#pragma ident	"@(#)strptr.c	1.12	08/05/31 SMI"
31
32#include "libelf.h"
33#include "decl.h"
34#include "msg.h"
35
36
37char *
38elf_strptr(Elf * elf, size_t ndx, size_t off)
39{
40	Elf_Scn *	s;
41	Elf_Data *	d;
42	char *		rc;
43
44	if (elf == 0)
45		return (0);
46
47#if defined(__APPLE__)
48	extern const char *elf_macho_str_off(size_t off);
49
50	if (elf->ed_kind == ELF_K_MACHO && (ndx == SHN_MACHO || ndx == SHN_MACHO_64))
51		return (char *)elf_macho_str_off(off);
52#endif /* __APPLE__ */
53
54	if ((s = elf_getscn(elf, ndx)) == 0) {
55		_elf_seterr(EREQ_STRSCN, 0);
56		return (0);
57	}
58	READLOCKS(elf, s)
59	if (elf->ed_class == ELFCLASS32) {
60		Elf32_Shdr* sh = (Elf32_Shdr*)s->s_shdr;
61
62		if ((sh == 0) || (sh->sh_type != SHT_STRTAB)) {
63			_elf_seterr(EREQ_STRSCN, 0);
64			READUNLOCKS(elf, s)
65			return (0);
66		}
67	} else if (elf->ed_class == ELFCLASS64) {
68		Elf64_Shdr* sh = (Elf64_Shdr*)s->s_shdr;
69
70		if ((sh == 0) || (sh->sh_type != SHT_STRTAB)) {
71			_elf_seterr(EREQ_STRSCN, 0);
72			READUNLOCKS(elf, s)
73			return (0);
74		}
75	} else {
76		_elf_seterr(EREQ_STRSCN, 0);
77		READUNLOCKS(elf, s)
78		return (0);
79	}
80
81
82	/*
83	 * If the layout bit is set, use the offsets and
84	 * sizes in the data buffers.  Otherwise, take
85	 * data buffers in order.
86	 */
87
88	d = 0;
89	if (elf->ed_uflags & ELF_F_LAYOUT) {
90		while ((d = _elf_locked_getdata(s, d)) != 0) {
91			if (d->d_buf == 0)
92				continue;
93			if ((off >= d->d_off) &&
94			    (off < d->d_off + d->d_size)) {
95				rc = (char *)d->d_buf + off - d->d_off;
96				READUNLOCKS(elf, s)
97				return (rc);
98			}
99		}
100	} else {
101		size_t	sz = 0, j;
102		while ((d = _elf_locked_getdata(s, d)) != 0) {
103			if (((j = d->d_align) > 1) && (sz % j != 0)) {
104				j -= sz % j;
105				sz += j;
106				if (off < j)
107					break;
108				off -= j;
109			}
110			if (d->d_buf != 0) {
111				if (off < d->d_size) {
112					rc = (char *)d->d_buf + off;
113					READUNLOCKS(elf, s)
114					return (rc);
115				}
116			}
117			sz += d->d_size;
118			if (off < d->d_size)
119				break;
120			off -= d->d_size;
121		}
122	}
123	_elf_seterr(EREQ_STROFF, 0);
124	READUNLOCKS(elf, s)
125	return (0);
126}
127