xref: /openbsd/usr.bin/nm/elf.c (revision e397383a)
1*e397383aSmickey /*	$OpenBSD: elf.c,v 1.9 2004/10/09 20:17:52 mickey Exp $	*/
2fd9f71a7Smickey 
3fd9f71a7Smickey /*
4fd9f71a7Smickey  * Copyright (c) 2003 Michael Shalayeff
5fd9f71a7Smickey  * All rights reserved.
6fd9f71a7Smickey  *
7fd9f71a7Smickey  * Redistribution and use in source and binary forms, with or without
8fd9f71a7Smickey  * modification, are permitted provided that the following conditions
9fd9f71a7Smickey  * are met:
10fd9f71a7Smickey  * 1. Redistributions of source code must retain the above copyright
11fd9f71a7Smickey  *    notice, this list of conditions and the following disclaimer.
12fd9f71a7Smickey  * 2. Redistributions in binary form must reproduce the above copyright
13fd9f71a7Smickey  *    notice, this list of conditions and the following disclaimer in the
14fd9f71a7Smickey  *    documentation and/or other materials provided with the distribution.
15fd9f71a7Smickey  *
16fd9f71a7Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17fd9f71a7Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18fd9f71a7Smickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19fd9f71a7Smickey  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20fd9f71a7Smickey  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21fd9f71a7Smickey  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22fd9f71a7Smickey  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23fd9f71a7Smickey  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24fd9f71a7Smickey  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25fd9f71a7Smickey  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26fd9f71a7Smickey  * THE POSSIBILITY OF SUCH DAMAGE.
27fd9f71a7Smickey  */
28fd9f71a7Smickey 
29fd9f71a7Smickey #if ELF_TARG_CLASS == ELFCLASS32
30fd9f71a7Smickey #define	swap_addr	swap32
31fd9f71a7Smickey #define	swap_off	swap32
32fd9f71a7Smickey #define	swap_sword	swap32
33fd9f71a7Smickey #define	swap_word	swap32
34fd9f71a7Smickey #define	swap_sxword	swap32
35fd9f71a7Smickey #define	swap_xword	swap32
36fd9f71a7Smickey #define	swap_half	swap16
37fd9f71a7Smickey #define	swap_quarter	swap16
38fd9f71a7Smickey #elif ELF_TARG_CLASS == ELFCLASS64
39fd9f71a7Smickey #define	swap_addr	swap64
40fd9f71a7Smickey #define	swap_off	swap64
41fd9f71a7Smickey #ifdef __alpha__
42fd9f71a7Smickey #define	swap_sword	swap64
43fd9f71a7Smickey #define	swap_word	swap64
44fd9f71a7Smickey #else
45fd9f71a7Smickey #define	swap_sword	swap32
46fd9f71a7Smickey #define	swap_word	swap32
47fd9f71a7Smickey #endif
48fd9f71a7Smickey #define	swap_sxword	swap64
49fd9f71a7Smickey #define	swap_xword	swap64
50fd9f71a7Smickey #define	swap_half	swap64
51fd9f71a7Smickey #define	swap_quarter	swap16
52fd9f71a7Smickey #else
53fd9f71a7Smickey #error "Unsupported ELF class"
54fd9f71a7Smickey #endif
55fd9f71a7Smickey 
56*e397383aSmickey #define	ELF_SDATA	".sdata"
5700f0c933Smickey #define	ELF_SBSS	".sbss"
5818752b6fSmickey #define	ELF_PLT		".plt"
5900f0c933Smickey 
60fd9f71a7Smickey int
61fd9f71a7Smickey elf_fix_header(Elf_Ehdr *eh)
62fd9f71a7Smickey {
63fd9f71a7Smickey 	/* nothing to do */
64fd9f71a7Smickey 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
65fd9f71a7Smickey 		return (0);
66fd9f71a7Smickey 
67fd9f71a7Smickey 	eh->e_type = swap16(eh->e_type);
68fd9f71a7Smickey 	eh->e_machine = swap16(eh->e_machine);
69fd9f71a7Smickey 	eh->e_version = swap32(eh->e_version);
70fd9f71a7Smickey 	eh->e_entry = swap_addr(eh->e_entry);
71fd9f71a7Smickey 	eh->e_phoff = swap_off(eh->e_phoff);
72fd9f71a7Smickey 	eh->e_shoff = swap_off(eh->e_shoff);
73fd9f71a7Smickey 	eh->e_flags = swap32(eh->e_flags);
74fd9f71a7Smickey 	eh->e_ehsize = swap16(eh->e_ehsize);
75fd9f71a7Smickey 	eh->e_phentsize = swap16(eh->e_phentsize);
76fd9f71a7Smickey 	eh->e_phnum = swap16(eh->e_phnum);
77fd9f71a7Smickey 	eh->e_shentsize = swap16(eh->e_shentsize);
78fd9f71a7Smickey 	eh->e_shnum = swap16(eh->e_shnum);
79fd9f71a7Smickey 	eh->e_shstrndx = swap16(eh->e_shstrndx);
80fd9f71a7Smickey 
81fd9f71a7Smickey 	return (1);
82fd9f71a7Smickey }
83fd9f71a7Smickey 
84fd9f71a7Smickey int
85fd9f71a7Smickey elf_fix_shdrs(Elf_Ehdr *eh, Elf_Shdr *shdr)
86fd9f71a7Smickey {
87fd9f71a7Smickey 	int i;
88fd9f71a7Smickey 
89fd9f71a7Smickey 	/* nothing to do */
90fd9f71a7Smickey 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
91fd9f71a7Smickey 		return (0);
92fd9f71a7Smickey 
93fd9f71a7Smickey 	for (i = eh->e_shnum; i--; shdr++) {
94fd9f71a7Smickey 		shdr->sh_name = swap32(shdr->sh_name);
95fd9f71a7Smickey 		shdr->sh_type = swap32(shdr->sh_type);
96fd9f71a7Smickey 		shdr->sh_flags = swap_xword(shdr->sh_flags);
97fd9f71a7Smickey 		shdr->sh_addr = swap_addr(shdr->sh_addr);
98fd9f71a7Smickey 		shdr->sh_offset = swap_off(shdr->sh_offset);
99fd9f71a7Smickey 		shdr->sh_size = swap_xword(shdr->sh_size);
100fd9f71a7Smickey 		shdr->sh_link = swap32(shdr->sh_link);
101fd9f71a7Smickey 		shdr->sh_info = swap32(shdr->sh_info);
102fd9f71a7Smickey 		shdr->sh_addralign = swap_xword(shdr->sh_addralign);
103fd9f71a7Smickey 		shdr->sh_entsize = swap_xword(shdr->sh_entsize);
104fd9f71a7Smickey 	}
105fd9f71a7Smickey 
106fd9f71a7Smickey 	return (1);
107fd9f71a7Smickey }
108fd9f71a7Smickey 
109fd9f71a7Smickey int
110fd9f71a7Smickey elf_fix_phdrs(Elf_Ehdr *eh, Elf_Phdr *phdr)
111fd9f71a7Smickey {
112fd9f71a7Smickey 	int i;
113fd9f71a7Smickey 
114fd9f71a7Smickey 	/* nothing to do */
115fd9f71a7Smickey 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
116fd9f71a7Smickey 		return (0);
117fd9f71a7Smickey 
118fd9f71a7Smickey 	for (i = eh->e_phnum; i--; phdr++) {
119fd9f71a7Smickey 		phdr->p_type = swap32(phdr->p_type);
120fd9f71a7Smickey 		phdr->p_flags = swap32(phdr->p_flags);
121fd9f71a7Smickey 		phdr->p_offset = swap_off(phdr->p_offset);
122fd9f71a7Smickey 		phdr->p_vaddr = swap_addr(phdr->p_vaddr);
123fd9f71a7Smickey 		phdr->p_paddr = swap_addr(phdr->p_paddr);
124fd9f71a7Smickey 		phdr->p_filesz = swap_xword(phdr->p_filesz);
125fd9f71a7Smickey 		phdr->p_memsz = swap_xword(phdr->p_memsz);
126fd9f71a7Smickey 		phdr->p_align = swap_xword(phdr->p_align);
127fd9f71a7Smickey 	}
128fd9f71a7Smickey 
129fd9f71a7Smickey 	return (1);
130fd9f71a7Smickey }
131fd9f71a7Smickey 
132fd9f71a7Smickey int
133fd9f71a7Smickey elf_fix_sym(Elf_Ehdr *eh, Elf_Sym *sym)
134fd9f71a7Smickey {
135fd9f71a7Smickey 	/* nothing to do */
136fd9f71a7Smickey 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
137fd9f71a7Smickey 		return (0);
138fd9f71a7Smickey 
139fd9f71a7Smickey 	sym->st_name = swap32(sym->st_name);
140fd9f71a7Smickey 	sym->st_shndx = swap16(sym->st_shndx);
141fd9f71a7Smickey 	sym->st_value = swap_addr(sym->st_value);
142fd9f71a7Smickey 	sym->st_size = swap_xword(sym->st_size);
143fd9f71a7Smickey 
144fd9f71a7Smickey 	return (1);
145fd9f71a7Smickey }
146fd9f71a7Smickey 
147*e397383aSmickey int
148*e397383aSmickey elf_shn2type(u_int shn, const char *sn)
149*e397383aSmickey {
150*e397383aSmickey 	switch (shn) {
151*e397383aSmickey #ifdef SHN_MIPS_SUNDEFINED
152*e397383aSmickey 	case SHN_MIPS_SUNDEFINED:
153*e397383aSmickey #endif
154*e397383aSmickey 	case SHN_UNDEF:
155*e397383aSmickey 		return (N_UNDF | N_EXT);
156*e397383aSmickey 	case SHN_ABS:
157*e397383aSmickey 		return (N_ABS);
158*e397383aSmickey #ifdef SHN_MIPS_ACOMMON
159*e397383aSmickey 	case SHN_MIPS_ACOMMON:
160*e397383aSmickey #endif
161*e397383aSmickey #ifdef SHN_MIPS_SCOMMON
162*e397383aSmickey 	case SHN_MIPS_SCOMMON:
163*e397383aSmickey #endif
164*e397383aSmickey 	case SHN_COMMON:
165*e397383aSmickey 		return (N_COMM);
166*e397383aSmickey #ifdef SHN_MIPS_TEXT
167*e397383aSmickey 	case SHN_MIPS_TEXT:
168*e397383aSmickey 		return (N_TEXT);
169*e397383aSmickey #endif
170*e397383aSmickey #ifdef SHN_MIPS_DATA
171*e397383aSmickey 	case SHN_MIPS_DATA:
172*e397383aSmickey 		return (N_DATA);
173*e397383aSmickey #endif
174*e397383aSmickey 	default:
175*e397383aSmickey 		/* beyond 8 a table-driven binsearch shall be used */
176*e397383aSmickey 		if (sn == NULL)
177*e397383aSmickey 			return (-1);
178*e397383aSmickey 		else if (!strcmp(sn, ELF_TEXT))
179*e397383aSmickey 			return (N_TEXT);
180*e397383aSmickey 		else if (!strcmp(sn, ELF_RODATA))
181*e397383aSmickey 			return (N_SIZE);
182*e397383aSmickey 		else if (!strcmp(sn, ELF_DATA))
183*e397383aSmickey 			return (N_DATA);
184*e397383aSmickey 		else if (!strcmp(sn, ELF_SDATA))
185*e397383aSmickey 			return (N_DATA);
186*e397383aSmickey 		else if (!strcmp(sn, ELF_BSS))
187*e397383aSmickey 			return (N_BSS);
188*e397383aSmickey 		else if (!strcmp(sn, ELF_SBSS))
189*e397383aSmickey 			return (N_BSS);
190*e397383aSmickey 		else if (!strncmp(sn, ELF_GOT, sizeof(ELF_GOT) - 1))
191*e397383aSmickey 			return (N_DATA);
192*e397383aSmickey 		else if (!strncmp(sn, ELF_PLT, sizeof(ELF_PLT) - 1))
193*e397383aSmickey 			return (N_DATA);
194*e397383aSmickey 		return (-1);
195*e397383aSmickey 	}
196*e397383aSmickey }
197*e397383aSmickey 
198fd9f71a7Smickey /*
199fd9f71a7Smickey  * Devise nlist's type from Elf_Sym.
200fd9f71a7Smickey  * XXX this task is done as well in libc and kvm_mkdb.
201fd9f71a7Smickey  */
202fd9f71a7Smickey int
203fd9f71a7Smickey elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr, struct nlist *np)
204fd9f71a7Smickey {
205*e397383aSmickey 	u_char stt;
206fd9f71a7Smickey 	const char *sn;
207*e397383aSmickey 	int type;
208fd9f71a7Smickey 
209fd9f71a7Smickey 	if (sym->st_shndx < eh->e_shnum)
210fd9f71a7Smickey 		sn = shstr + shdr[sym->st_shndx].sh_name;
211fd9f71a7Smickey 	else
212*e397383aSmickey 		sn = NULL;
21318752b6fSmickey #if 0
21418752b6fSmickey 	{
21518752b6fSmickey 		extern char *stab;
216*e397383aSmickey 		printf("%d:%s %d %s\n", sym->st_shndx, sn? sn : "",
21718752b6fSmickey 		    ELF_ST_TYPE(sym->st_info), stab + sym->st_name);
21818752b6fSmickey 	}
21918752b6fSmickey #endif
220fd9f71a7Smickey 
221*e397383aSmickey 	switch (stt = ELF_ST_TYPE(sym->st_info)) {
222*e397383aSmickey 	case STT_NOTYPE:
223629deeacSmickey 	case STT_OBJECT:
224*e397383aSmickey 		type = elf_shn2type(sym->st_shndx, sn);
225*e397383aSmickey 		if (type < 0) {
226*e397383aSmickey 			if (sn == NULL)
227*e397383aSmickey 				np->n_other = '?';
228*e397383aSmickey 			else
229*e397383aSmickey 				np->n_type = stt == STT_NOTYPE? N_COMM : N_DATA;
230*e397383aSmickey 		} else {
231*e397383aSmickey 			/* a hack for .rodata check (; */
232*e397383aSmickey 			if (type == N_SIZE) {
233629deeacSmickey 				np->n_type = N_DATA;
234629deeacSmickey 				np->n_other = 'r';
235*e397383aSmickey 			} else
236*e397383aSmickey 				np->n_type = type;
237629deeacSmickey 		}
238629deeacSmickey 		break;
239629deeacSmickey 
240fd9f71a7Smickey 	case STT_FUNC:
241*e397383aSmickey 		type = elf_shn2type(sym->st_shndx, NULL);
242*e397383aSmickey 		np->n_type = type < 0? N_TEXT : type;
243fd9f71a7Smickey 		if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
244fd9f71a7Smickey 			np->n_type = N_INDR;
245fd9f71a7Smickey 			np->n_other = 'W';
246*e397383aSmickey 		} else if (sn != NULL &&
247*e397383aSmickey 		    strcmp(sn, ELF_INIT) &&
24818752b6fSmickey 		    strcmp(sn, ELF_TEXT) &&
24918752b6fSmickey 		    strcmp(sn, ELF_FINI))	/* XXX GNU compat */
250fd9f71a7Smickey 			np->n_other = '?';
251fd9f71a7Smickey 		break;
252fd9f71a7Smickey 
253629deeacSmickey 	case STT_SECTION:
254*e397383aSmickey 		type = elf_shn2type(sym->st_shndx, NULL);
255*e397383aSmickey 		if (type < 0)
256629deeacSmickey 			np->n_other = '?';
257*e397383aSmickey 		else
258*e397383aSmickey 			np->n_type = type;
259fd9f71a7Smickey 		break;
260fd9f71a7Smickey 
261fd9f71a7Smickey 	case STT_FILE:
262fd9f71a7Smickey 		np->n_type = N_FN | N_EXT;
263fd9f71a7Smickey 		break;
264fd9f71a7Smickey 
265fd9f71a7Smickey 	/* XXX how about cross-nm then ? */
266fd9f71a7Smickey #ifdef STT_PARISC_MILLI
267fd9f71a7Smickey 	case STT_PARISC_MILLI:
268fd9f71a7Smickey 		np->n_type = N_TEXT;
269fd9f71a7Smickey 		break;
270fd9f71a7Smickey #endif
271fd9f71a7Smickey 	default:
272fd9f71a7Smickey 		np->n_other = '?';
273fd9f71a7Smickey 		break;
274fd9f71a7Smickey 	}
275fd9f71a7Smickey 	if (np->n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
276fd9f71a7Smickey 		np->n_type |= N_EXT;
277fd9f71a7Smickey 		if (np->n_other)
278fd9f71a7Smickey 			np->n_other = toupper(np->n_other);
279fd9f71a7Smickey 	}
280fd9f71a7Smickey 
281fd9f71a7Smickey 	return (0);
282fd9f71a7Smickey }
283