xref: /dflybsd-src/contrib/gdb-7/libiberty/simple-object-elf.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* simple-object-elf.c -- routines to manipulate ELF object files.
286d7f5d3SJohn Marino    Copyright 2010 Free Software Foundation, Inc.
386d7f5d3SJohn Marino    Written by Ian Lance Taylor, Google.
486d7f5d3SJohn Marino 
586d7f5d3SJohn Marino This program is free software; you can redistribute it and/or modify it
686d7f5d3SJohn Marino under the terms of the GNU General Public License as published by the
786d7f5d3SJohn Marino Free Software Foundation; either version 2, or (at your option) any
886d7f5d3SJohn Marino later version.
986d7f5d3SJohn Marino 
1086d7f5d3SJohn Marino This program is distributed in the hope that it will be useful,
1186d7f5d3SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
1286d7f5d3SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1386d7f5d3SJohn Marino GNU General Public License for more details.
1486d7f5d3SJohn Marino 
1586d7f5d3SJohn Marino You should have received a copy of the GNU General Public License
1686d7f5d3SJohn Marino along with this program; if not, write to the Free Software
1786d7f5d3SJohn Marino Foundation, 51 Franklin Street - Fifth Floor,
1886d7f5d3SJohn Marino Boston, MA 02110-1301, USA.  */
1986d7f5d3SJohn Marino 
2086d7f5d3SJohn Marino #include "config.h"
2186d7f5d3SJohn Marino #include "libiberty.h"
2286d7f5d3SJohn Marino #include "simple-object.h"
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino #include <errno.h>
2586d7f5d3SJohn Marino #include <stddef.h>
2686d7f5d3SJohn Marino 
2786d7f5d3SJohn Marino #ifdef HAVE_STDLIB_H
2886d7f5d3SJohn Marino #include <stdlib.h>
2986d7f5d3SJohn Marino #endif
3086d7f5d3SJohn Marino 
3186d7f5d3SJohn Marino #ifdef HAVE_STDINT_H
3286d7f5d3SJohn Marino #include <stdint.h>
3386d7f5d3SJohn Marino #endif
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino #ifdef HAVE_STRING_H
3686d7f5d3SJohn Marino #include <string.h>
3786d7f5d3SJohn Marino #endif
3886d7f5d3SJohn Marino 
3986d7f5d3SJohn Marino #ifdef HAVE_INTTYPES_H
4086d7f5d3SJohn Marino #include <inttypes.h>
4186d7f5d3SJohn Marino #endif
4286d7f5d3SJohn Marino 
4386d7f5d3SJohn Marino #include "simple-object-common.h"
4486d7f5d3SJohn Marino 
4586d7f5d3SJohn Marino /* ELF structures and constants.  */
4686d7f5d3SJohn Marino 
4786d7f5d3SJohn Marino /* 32-bit ELF file header.  */
4886d7f5d3SJohn Marino 
4986d7f5d3SJohn Marino typedef struct {
5086d7f5d3SJohn Marino   unsigned char	e_ident[16];		/* ELF "magic number" */
5186d7f5d3SJohn Marino   unsigned char	e_type[2];		/* Identifies object file type */
5286d7f5d3SJohn Marino   unsigned char	e_machine[2];		/* Specifies required architecture */
5386d7f5d3SJohn Marino   unsigned char	e_version[4];		/* Identifies object file version */
5486d7f5d3SJohn Marino   unsigned char	e_entry[4];		/* Entry point virtual address */
5586d7f5d3SJohn Marino   unsigned char	e_phoff[4];		/* Program header table file offset */
5686d7f5d3SJohn Marino   unsigned char	e_shoff[4];		/* Section header table file offset */
5786d7f5d3SJohn Marino   unsigned char	e_flags[4];		/* Processor-specific flags */
5886d7f5d3SJohn Marino   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
5986d7f5d3SJohn Marino   unsigned char	e_phentsize[2];		/* Program header table entry size */
6086d7f5d3SJohn Marino   unsigned char	e_phnum[2];		/* Program header table entry count */
6186d7f5d3SJohn Marino   unsigned char	e_shentsize[2];		/* Section header table entry size */
6286d7f5d3SJohn Marino   unsigned char	e_shnum[2];		/* Section header table entry count */
6386d7f5d3SJohn Marino   unsigned char	e_shstrndx[2];		/* Section header string table index */
6486d7f5d3SJohn Marino } Elf32_External_Ehdr;
6586d7f5d3SJohn Marino 
6686d7f5d3SJohn Marino /* 64-bit ELF file header.  */
6786d7f5d3SJohn Marino 
6886d7f5d3SJohn Marino typedef struct {
6986d7f5d3SJohn Marino   unsigned char	e_ident[16];		/* ELF "magic number" */
7086d7f5d3SJohn Marino   unsigned char	e_type[2];		/* Identifies object file type */
7186d7f5d3SJohn Marino   unsigned char	e_machine[2];		/* Specifies required architecture */
7286d7f5d3SJohn Marino   unsigned char	e_version[4];		/* Identifies object file version */
7386d7f5d3SJohn Marino   unsigned char	e_entry[8];		/* Entry point virtual address */
7486d7f5d3SJohn Marino   unsigned char	e_phoff[8];		/* Program header table file offset */
7586d7f5d3SJohn Marino   unsigned char	e_shoff[8];		/* Section header table file offset */
7686d7f5d3SJohn Marino   unsigned char	e_flags[4];		/* Processor-specific flags */
7786d7f5d3SJohn Marino   unsigned char	e_ehsize[2];		/* ELF header size in bytes */
7886d7f5d3SJohn Marino   unsigned char	e_phentsize[2];		/* Program header table entry size */
7986d7f5d3SJohn Marino   unsigned char	e_phnum[2];		/* Program header table entry count */
8086d7f5d3SJohn Marino   unsigned char	e_shentsize[2];		/* Section header table entry size */
8186d7f5d3SJohn Marino   unsigned char	e_shnum[2];		/* Section header table entry count */
8286d7f5d3SJohn Marino   unsigned char	e_shstrndx[2];		/* Section header string table index */
8386d7f5d3SJohn Marino } Elf64_External_Ehdr;
8486d7f5d3SJohn Marino 
8586d7f5d3SJohn Marino /* Indexes and values in e_ident field of Ehdr.  */
8686d7f5d3SJohn Marino 
8786d7f5d3SJohn Marino #define EI_MAG0		0	/* File identification byte 0 index */
8886d7f5d3SJohn Marino #define ELFMAG0		   0x7F	/* Magic number byte 0 */
8986d7f5d3SJohn Marino 
9086d7f5d3SJohn Marino #define EI_MAG1		1	/* File identification byte 1 index */
9186d7f5d3SJohn Marino #define ELFMAG1		    'E'	/* Magic number byte 1 */
9286d7f5d3SJohn Marino 
9386d7f5d3SJohn Marino #define EI_MAG2		2	/* File identification byte 2 index */
9486d7f5d3SJohn Marino #define ELFMAG2		    'L'	/* Magic number byte 2 */
9586d7f5d3SJohn Marino 
9686d7f5d3SJohn Marino #define EI_MAG3		3	/* File identification byte 3 index */
9786d7f5d3SJohn Marino #define ELFMAG3		    'F'	/* Magic number byte 3 */
9886d7f5d3SJohn Marino 
9986d7f5d3SJohn Marino #define EI_CLASS	4	/* File class */
10086d7f5d3SJohn Marino #define ELFCLASSNONE	      0	/* Invalid class */
10186d7f5d3SJohn Marino #define ELFCLASS32	      1	/* 32-bit objects */
10286d7f5d3SJohn Marino #define ELFCLASS64	      2	/* 64-bit objects */
10386d7f5d3SJohn Marino 
10486d7f5d3SJohn Marino #define EI_DATA		5	/* Data encoding */
10586d7f5d3SJohn Marino #define ELFDATANONE	      0	/* Invalid data encoding */
10686d7f5d3SJohn Marino #define ELFDATA2LSB	      1	/* 2's complement, little endian */
10786d7f5d3SJohn Marino #define ELFDATA2MSB	      2	/* 2's complement, big endian */
10886d7f5d3SJohn Marino 
10986d7f5d3SJohn Marino #define EI_VERSION	6	/* File version */
11086d7f5d3SJohn Marino #define EV_CURRENT	1		/* Current version */
11186d7f5d3SJohn Marino 
11286d7f5d3SJohn Marino #define EI_OSABI	7	/* Operating System/ABI indication */
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino /* Values for e_type field of Ehdr.  */
11586d7f5d3SJohn Marino 
11686d7f5d3SJohn Marino #define ET_REL		1	/* Relocatable file */
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino /* Values for e_machine field of Ehdr.  */
11986d7f5d3SJohn Marino 
12086d7f5d3SJohn Marino #define EM_SPARC	  2	/* SUN SPARC */
12186d7f5d3SJohn Marino #define EM_SPARC32PLUS	 18	/* Sun's "v8plus" */
12286d7f5d3SJohn Marino 
12386d7f5d3SJohn Marino /* Special section index values.  */
12486d7f5d3SJohn Marino 
12586d7f5d3SJohn Marino #define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
12686d7f5d3SJohn Marino #define SHN_XINDEX	0xFFFF		/* Section index is held elsewhere */
12786d7f5d3SJohn Marino 
12886d7f5d3SJohn Marino /* 32-bit ELF program header.  */
12986d7f5d3SJohn Marino 
13086d7f5d3SJohn Marino typedef struct {
13186d7f5d3SJohn Marino   unsigned char	p_type[4];		/* Identifies program segment type */
13286d7f5d3SJohn Marino   unsigned char	p_offset[4];		/* Segment file offset */
13386d7f5d3SJohn Marino   unsigned char	p_vaddr[4];		/* Segment virtual address */
13486d7f5d3SJohn Marino   unsigned char	p_paddr[4];		/* Segment physical address */
13586d7f5d3SJohn Marino   unsigned char	p_filesz[4];		/* Segment size in file */
13686d7f5d3SJohn Marino   unsigned char	p_memsz[4];		/* Segment size in memory */
13786d7f5d3SJohn Marino   unsigned char	p_flags[4];		/* Segment flags */
13886d7f5d3SJohn Marino   unsigned char	p_align[4];		/* Segment alignment, file & memory */
13986d7f5d3SJohn Marino } Elf32_External_Phdr;
14086d7f5d3SJohn Marino 
14186d7f5d3SJohn Marino /* 64-bit ELF program header.  */
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino typedef struct {
14486d7f5d3SJohn Marino   unsigned char	p_type[4];		/* Identifies program segment type */
14586d7f5d3SJohn Marino   unsigned char	p_flags[4];		/* Segment flags */
14686d7f5d3SJohn Marino   unsigned char	p_offset[8];		/* Segment file offset */
14786d7f5d3SJohn Marino   unsigned char	p_vaddr[8];		/* Segment virtual address */
14886d7f5d3SJohn Marino   unsigned char	p_paddr[8];		/* Segment physical address */
14986d7f5d3SJohn Marino   unsigned char	p_filesz[8];		/* Segment size in file */
15086d7f5d3SJohn Marino   unsigned char	p_memsz[8];		/* Segment size in memory */
15186d7f5d3SJohn Marino   unsigned char	p_align[8];		/* Segment alignment, file & memory */
15286d7f5d3SJohn Marino } Elf64_External_Phdr;
15386d7f5d3SJohn Marino 
15486d7f5d3SJohn Marino /* 32-bit ELF section header */
15586d7f5d3SJohn Marino 
15686d7f5d3SJohn Marino typedef struct {
15786d7f5d3SJohn Marino   unsigned char	sh_name[4];		/* Section name, index in string tbl */
15886d7f5d3SJohn Marino   unsigned char	sh_type[4];		/* Type of section */
15986d7f5d3SJohn Marino   unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
16086d7f5d3SJohn Marino   unsigned char	sh_addr[4];		/* Section virtual addr at execution */
16186d7f5d3SJohn Marino   unsigned char	sh_offset[4];		/* Section file offset */
16286d7f5d3SJohn Marino   unsigned char	sh_size[4];		/* Size of section in bytes */
16386d7f5d3SJohn Marino   unsigned char	sh_link[4];		/* Index of another section */
16486d7f5d3SJohn Marino   unsigned char	sh_info[4];		/* Additional section information */
16586d7f5d3SJohn Marino   unsigned char	sh_addralign[4];	/* Section alignment */
16686d7f5d3SJohn Marino   unsigned char	sh_entsize[4];		/* Entry size if section holds table */
16786d7f5d3SJohn Marino } Elf32_External_Shdr;
16886d7f5d3SJohn Marino 
16986d7f5d3SJohn Marino /* 64-bit ELF section header.  */
17086d7f5d3SJohn Marino 
17186d7f5d3SJohn Marino typedef struct {
17286d7f5d3SJohn Marino   unsigned char	sh_name[4];		/* Section name, index in string tbl */
17386d7f5d3SJohn Marino   unsigned char	sh_type[4];		/* Type of section */
17486d7f5d3SJohn Marino   unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
17586d7f5d3SJohn Marino   unsigned char	sh_addr[8];		/* Section virtual addr at execution */
17686d7f5d3SJohn Marino   unsigned char	sh_offset[8];		/* Section file offset */
17786d7f5d3SJohn Marino   unsigned char	sh_size[8];		/* Size of section in bytes */
17886d7f5d3SJohn Marino   unsigned char	sh_link[4];		/* Index of another section */
17986d7f5d3SJohn Marino   unsigned char	sh_info[4];		/* Additional section information */
18086d7f5d3SJohn Marino   unsigned char	sh_addralign[8];	/* Section alignment */
18186d7f5d3SJohn Marino   unsigned char	sh_entsize[8];		/* Entry size if section holds table */
18286d7f5d3SJohn Marino } Elf64_External_Shdr;
18386d7f5d3SJohn Marino 
18486d7f5d3SJohn Marino /* Values for sh_type field.  */
18586d7f5d3SJohn Marino 
18686d7f5d3SJohn Marino #define SHT_PROGBITS	1		/* Program data */
18786d7f5d3SJohn Marino #define SHT_STRTAB	3		/* A string table */
18886d7f5d3SJohn Marino 
18986d7f5d3SJohn Marino /* Functions to fetch and store different ELF types, depending on the
19086d7f5d3SJohn Marino    endianness and size.  */
19186d7f5d3SJohn Marino 
19286d7f5d3SJohn Marino struct elf_type_functions
19386d7f5d3SJohn Marino {
19486d7f5d3SJohn Marino   unsigned short (*fetch_Elf_Half) (const unsigned char *);
19586d7f5d3SJohn Marino   unsigned int (*fetch_Elf_Word) (const unsigned char *);
19686d7f5d3SJohn Marino   ulong_type (*fetch_Elf_Addr) (const unsigned char *);
19786d7f5d3SJohn Marino   void (*set_Elf_Half) (unsigned char *, unsigned short);
19886d7f5d3SJohn Marino   void (*set_Elf_Word) (unsigned char *, unsigned int);
19986d7f5d3SJohn Marino   void (*set_Elf_Addr) (unsigned char *, ulong_type);
20086d7f5d3SJohn Marino };
20186d7f5d3SJohn Marino 
20286d7f5d3SJohn Marino static const struct elf_type_functions elf_big_32_functions =
20386d7f5d3SJohn Marino {
20486d7f5d3SJohn Marino   simple_object_fetch_big_16,
20586d7f5d3SJohn Marino   simple_object_fetch_big_32,
20686d7f5d3SJohn Marino   simple_object_fetch_big_32_ulong,
20786d7f5d3SJohn Marino   simple_object_set_big_16,
20886d7f5d3SJohn Marino   simple_object_set_big_32,
20986d7f5d3SJohn Marino   simple_object_set_big_32_ulong
21086d7f5d3SJohn Marino };
21186d7f5d3SJohn Marino 
21286d7f5d3SJohn Marino static const struct elf_type_functions elf_little_32_functions =
21386d7f5d3SJohn Marino {
21486d7f5d3SJohn Marino   simple_object_fetch_little_16,
21586d7f5d3SJohn Marino   simple_object_fetch_little_32,
21686d7f5d3SJohn Marino   simple_object_fetch_little_32_ulong,
21786d7f5d3SJohn Marino   simple_object_set_little_16,
21886d7f5d3SJohn Marino   simple_object_set_little_32,
21986d7f5d3SJohn Marino   simple_object_set_little_32_ulong
22086d7f5d3SJohn Marino };
22186d7f5d3SJohn Marino 
22286d7f5d3SJohn Marino #ifdef UNSIGNED_64BIT_TYPE
22386d7f5d3SJohn Marino 
22486d7f5d3SJohn Marino static const struct elf_type_functions elf_big_64_functions =
22586d7f5d3SJohn Marino {
22686d7f5d3SJohn Marino   simple_object_fetch_big_16,
22786d7f5d3SJohn Marino   simple_object_fetch_big_32,
22886d7f5d3SJohn Marino   simple_object_fetch_big_64,
22986d7f5d3SJohn Marino   simple_object_set_big_16,
23086d7f5d3SJohn Marino   simple_object_set_big_32,
23186d7f5d3SJohn Marino   simple_object_set_big_64
23286d7f5d3SJohn Marino };
23386d7f5d3SJohn Marino 
23486d7f5d3SJohn Marino static const struct elf_type_functions elf_little_64_functions =
23586d7f5d3SJohn Marino {
23686d7f5d3SJohn Marino   simple_object_fetch_little_16,
23786d7f5d3SJohn Marino   simple_object_fetch_little_32,
23886d7f5d3SJohn Marino   simple_object_fetch_little_64,
23986d7f5d3SJohn Marino   simple_object_set_little_16,
24086d7f5d3SJohn Marino   simple_object_set_little_32,
24186d7f5d3SJohn Marino   simple_object_set_little_64
24286d7f5d3SJohn Marino };
24386d7f5d3SJohn Marino 
24486d7f5d3SJohn Marino #endif
24586d7f5d3SJohn Marino 
24686d7f5d3SJohn Marino /* Hideous macro to fetch the value of a field from an external ELF
24786d7f5d3SJohn Marino    struct of some sort.  TYPEFUNCS is the set of type functions.
24886d7f5d3SJohn Marino    BUFFER points to the external data.  STRUCTTYPE is the appropriate
24986d7f5d3SJohn Marino    struct type.  FIELD is a field within the struct.  TYPE is the type
25086d7f5d3SJohn Marino    of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr.  */
25186d7f5d3SJohn Marino 
25286d7f5d3SJohn Marino #define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \
25386d7f5d3SJohn Marino   ((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD)))
25486d7f5d3SJohn Marino 
25586d7f5d3SJohn Marino /* Even more hideous macro to fetch the value of FIELD from BUFFER.
25686d7f5d3SJohn Marino    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
25786d7f5d3SJohn Marino    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
25886d7f5d3SJohn Marino    the struct.  TYPE is the type of the field in the struct: Elf_Half,
25986d7f5d3SJohn Marino    Elf_Word, or Elf_Addr.  */
26086d7f5d3SJohn Marino 
26186d7f5d3SJohn Marino #define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER,	\
26286d7f5d3SJohn Marino 			      FIELD, TYPE)				\
26386d7f5d3SJohn Marino   ELF_FETCH_STRUCT_FIELD (TYPEFUNCS,					\
26486d7f5d3SJohn Marino 			  Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
26586d7f5d3SJohn Marino 			  FIELD, BUFFER, TYPE)
26686d7f5d3SJohn Marino 
26786d7f5d3SJohn Marino /* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value.  */
26886d7f5d3SJohn Marino 
26986d7f5d3SJohn Marino #define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER,		\
27086d7f5d3SJohn Marino 			FIELD, TYPE)					\
27186d7f5d3SJohn Marino   ((CLASS) == ELFCLASS32						\
27286d7f5d3SJohn Marino     ? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
27386d7f5d3SJohn Marino 			     TYPE)					\
27486d7f5d3SJohn Marino     : ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
27586d7f5d3SJohn Marino 			     TYPE))
27686d7f5d3SJohn Marino 
27786d7f5d3SJohn Marino /* Hideous macro to set the value of a field in an external ELF
27886d7f5d3SJohn Marino    structure to VAL.  TYPEFUNCS is the set of type functions.  BUFFER
27986d7f5d3SJohn Marino    points to the external data.  STRUCTTYPE is the appropriate
28086d7f5d3SJohn Marino    structure type.  FIELD is a field within the struct.  TYPE is the
28186d7f5d3SJohn Marino    type of the field in the struct: Elf_Half, Elf_Word, or
28286d7f5d3SJohn Marino    Elf_Addr.  */
28386d7f5d3SJohn Marino 
28486d7f5d3SJohn Marino #define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \
28586d7f5d3SJohn Marino   (TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL))
28686d7f5d3SJohn Marino 
28786d7f5d3SJohn Marino /* Even more hideous macro to set the value of FIELD in BUFFER to VAL.
28886d7f5d3SJohn Marino    SIZE is 32 or 64.  STRUCTTYPE is the name of the struct from
28986d7f5d3SJohn Marino    elf/external.h: Ehdr, Shdr, etc.  FIELD is the name of a field in
29086d7f5d3SJohn Marino    the struct.  TYPE is the type of the field in the struct: Elf_Half,
29186d7f5d3SJohn Marino    Elf_Word, or Elf_Addr.  */
29286d7f5d3SJohn Marino 
29386d7f5d3SJohn Marino #define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \
29486d7f5d3SJohn Marino 			    TYPE, VAL)					\
29586d7f5d3SJohn Marino   ELF_SET_STRUCT_FIELD (TYPEFUNCS,					\
29686d7f5d3SJohn Marino 			Elf ## SIZE ## _External_ ## STRUCTTYPE,	\
29786d7f5d3SJohn Marino 			FIELD, BUFFER, TYPE, VAL)
29886d7f5d3SJohn Marino 
29986d7f5d3SJohn Marino /* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value.  */
30086d7f5d3SJohn Marino 
30186d7f5d3SJohn Marino #define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD,	\
30286d7f5d3SJohn Marino 		      TYPE, VAL)					\
30386d7f5d3SJohn Marino   ((CLASS) == ELFCLASS32						\
30486d7f5d3SJohn Marino     ? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD,	\
30586d7f5d3SJohn Marino 			   TYPE, VAL)					\
30686d7f5d3SJohn Marino     : ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD,	\
30786d7f5d3SJohn Marino 			   TYPE, VAL))
30886d7f5d3SJohn Marino 
30986d7f5d3SJohn Marino /* Private data for an simple_object_read.  */
31086d7f5d3SJohn Marino 
31186d7f5d3SJohn Marino struct simple_object_elf_read
31286d7f5d3SJohn Marino {
31386d7f5d3SJohn Marino   /* Type functions.  */
31486d7f5d3SJohn Marino   const struct elf_type_functions* type_functions;
31586d7f5d3SJohn Marino   /* Elf data.  */
31686d7f5d3SJohn Marino   unsigned char ei_data;
31786d7f5d3SJohn Marino   /* Elf class.  */
31886d7f5d3SJohn Marino   unsigned char ei_class;
31986d7f5d3SJohn Marino   /* ELF OS ABI.  */
32086d7f5d3SJohn Marino   unsigned char ei_osabi;
32186d7f5d3SJohn Marino   /* Elf machine number.  */
32286d7f5d3SJohn Marino   unsigned short machine;
32386d7f5d3SJohn Marino   /* Processor specific flags.  */
32486d7f5d3SJohn Marino   unsigned int flags;
32586d7f5d3SJohn Marino   /* File offset of section headers.  */
32686d7f5d3SJohn Marino   ulong_type shoff;
32786d7f5d3SJohn Marino   /* Number of sections.  */
32886d7f5d3SJohn Marino   unsigned int shnum;
32986d7f5d3SJohn Marino   /* Index of string table section header.  */
33086d7f5d3SJohn Marino   unsigned int shstrndx;
33186d7f5d3SJohn Marino };
33286d7f5d3SJohn Marino 
33386d7f5d3SJohn Marino /* Private data for an simple_object_attributes.  */
33486d7f5d3SJohn Marino 
33586d7f5d3SJohn Marino struct simple_object_elf_attributes
33686d7f5d3SJohn Marino {
33786d7f5d3SJohn Marino   /* Type functions.  */
33886d7f5d3SJohn Marino   const struct elf_type_functions* type_functions;
33986d7f5d3SJohn Marino   /* Elf data.  */
34086d7f5d3SJohn Marino   unsigned char ei_data;
34186d7f5d3SJohn Marino   /* Elf class.  */
34286d7f5d3SJohn Marino   unsigned char ei_class;
34386d7f5d3SJohn Marino   /* ELF OS ABI.  */
34486d7f5d3SJohn Marino   unsigned char ei_osabi;
34586d7f5d3SJohn Marino   /* Elf machine number.  */
34686d7f5d3SJohn Marino   unsigned short machine;
34786d7f5d3SJohn Marino   /* Processor specific flags.  */
34886d7f5d3SJohn Marino   unsigned int flags;
34986d7f5d3SJohn Marino };
35086d7f5d3SJohn Marino 
35186d7f5d3SJohn Marino /* See if we have an ELF file.  */
35286d7f5d3SJohn Marino 
35386d7f5d3SJohn Marino static void *
simple_object_elf_match(unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],int descriptor,off_t offset,const char * segment_name ATTRIBUTE_UNUSED,const char ** errmsg,int * err)35486d7f5d3SJohn Marino simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
35586d7f5d3SJohn Marino 			 int descriptor, off_t offset,
35686d7f5d3SJohn Marino 			 const char *segment_name ATTRIBUTE_UNUSED,
35786d7f5d3SJohn Marino 			 const char **errmsg, int *err)
35886d7f5d3SJohn Marino {
35986d7f5d3SJohn Marino   unsigned char ei_data;
36086d7f5d3SJohn Marino   unsigned char ei_class;
36186d7f5d3SJohn Marino   const struct elf_type_functions *type_functions;
36286d7f5d3SJohn Marino   unsigned char ehdr[sizeof (Elf64_External_Ehdr)];
36386d7f5d3SJohn Marino   struct simple_object_elf_read *eor;
36486d7f5d3SJohn Marino 
36586d7f5d3SJohn Marino   if (header[EI_MAG0] != ELFMAG0
36686d7f5d3SJohn Marino       || header[EI_MAG1] != ELFMAG1
36786d7f5d3SJohn Marino       || header[EI_MAG2] != ELFMAG2
36886d7f5d3SJohn Marino       || header[EI_MAG3] != ELFMAG3
36986d7f5d3SJohn Marino       || header[EI_VERSION] != EV_CURRENT)
37086d7f5d3SJohn Marino     {
37186d7f5d3SJohn Marino       *errmsg = NULL;
37286d7f5d3SJohn Marino       *err = 0;
37386d7f5d3SJohn Marino       return NULL;
37486d7f5d3SJohn Marino     }
37586d7f5d3SJohn Marino 
37686d7f5d3SJohn Marino   ei_data = header[EI_DATA];
37786d7f5d3SJohn Marino   if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB)
37886d7f5d3SJohn Marino     {
37986d7f5d3SJohn Marino       *errmsg = "unknown ELF endianness";
38086d7f5d3SJohn Marino       *err = 0;
38186d7f5d3SJohn Marino       return NULL;
38286d7f5d3SJohn Marino     }
38386d7f5d3SJohn Marino 
38486d7f5d3SJohn Marino   ei_class = header[EI_CLASS];
38586d7f5d3SJohn Marino   switch (ei_class)
38686d7f5d3SJohn Marino     {
38786d7f5d3SJohn Marino     case ELFCLASS32:
38886d7f5d3SJohn Marino       type_functions = (ei_data == ELFDATA2LSB
38986d7f5d3SJohn Marino 			? &elf_little_32_functions
39086d7f5d3SJohn Marino 			: &elf_big_32_functions);
39186d7f5d3SJohn Marino       break;
39286d7f5d3SJohn Marino 
39386d7f5d3SJohn Marino     case ELFCLASS64:
39486d7f5d3SJohn Marino #ifndef UNSIGNED_64BIT_TYPE
39586d7f5d3SJohn Marino       *errmsg = "64-bit ELF objects not supported";
39686d7f5d3SJohn Marino       *err = 0;
39786d7f5d3SJohn Marino       return NULL;
39886d7f5d3SJohn Marino #else
39986d7f5d3SJohn Marino       type_functions = (ei_data == ELFDATA2LSB
40086d7f5d3SJohn Marino 			? &elf_little_64_functions
40186d7f5d3SJohn Marino 			: &elf_big_64_functions);
40286d7f5d3SJohn Marino       break;
40386d7f5d3SJohn Marino #endif
40486d7f5d3SJohn Marino 
40586d7f5d3SJohn Marino     default:
40686d7f5d3SJohn Marino       *errmsg = "unrecognized ELF size";
40786d7f5d3SJohn Marino       *err = 0;
40886d7f5d3SJohn Marino       return NULL;
40986d7f5d3SJohn Marino     }
41086d7f5d3SJohn Marino 
41186d7f5d3SJohn Marino   if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr,
41286d7f5d3SJohn Marino 				    errmsg, err))
41386d7f5d3SJohn Marino     return NULL;
41486d7f5d3SJohn Marino 
41586d7f5d3SJohn Marino   eor = XNEW (struct simple_object_elf_read);
41686d7f5d3SJohn Marino   eor->type_functions = type_functions;
41786d7f5d3SJohn Marino   eor->ei_data = ei_data;
41886d7f5d3SJohn Marino   eor->ei_class = ei_class;
41986d7f5d3SJohn Marino   eor->ei_osabi = header[EI_OSABI];
42086d7f5d3SJohn Marino   eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42186d7f5d3SJohn Marino 				  e_machine, Elf_Half);
42286d7f5d3SJohn Marino   eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42386d7f5d3SJohn Marino 				e_flags, Elf_Word);
42486d7f5d3SJohn Marino   eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42586d7f5d3SJohn Marino 				e_shoff, Elf_Addr);
42686d7f5d3SJohn Marino   eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42786d7f5d3SJohn Marino 				e_shnum, Elf_Half);
42886d7f5d3SJohn Marino   eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr,
42986d7f5d3SJohn Marino 				   e_shstrndx, Elf_Half);
43086d7f5d3SJohn Marino 
43186d7f5d3SJohn Marino   if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX)
43286d7f5d3SJohn Marino       && eor->shoff != 0)
43386d7f5d3SJohn Marino     {
43486d7f5d3SJohn Marino       unsigned char shdr[sizeof (Elf64_External_Shdr)];
43586d7f5d3SJohn Marino 
43686d7f5d3SJohn Marino       /* Object file has more than 0xffff sections.  */
43786d7f5d3SJohn Marino 
43886d7f5d3SJohn Marino       if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr,
43986d7f5d3SJohn Marino 					(ei_class == ELFCLASS32
44086d7f5d3SJohn Marino 					 ? sizeof (Elf32_External_Shdr)
44186d7f5d3SJohn Marino 					 : sizeof (Elf64_External_Shdr)),
44286d7f5d3SJohn Marino 					errmsg, err))
44386d7f5d3SJohn Marino 	{
44486d7f5d3SJohn Marino 	  XDELETE (eor);
44586d7f5d3SJohn Marino 	  return NULL;
44686d7f5d3SJohn Marino 	}
44786d7f5d3SJohn Marino 
44886d7f5d3SJohn Marino       if (eor->shnum == 0)
44986d7f5d3SJohn Marino 	eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
45086d7f5d3SJohn Marino 				      shdr, sh_size, Elf_Addr);
45186d7f5d3SJohn Marino 
45286d7f5d3SJohn Marino       if (eor->shstrndx == SHN_XINDEX)
45386d7f5d3SJohn Marino 	{
45486d7f5d3SJohn Marino 	  eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
45586d7f5d3SJohn Marino 					   shdr, sh_link, Elf_Word);
45686d7f5d3SJohn Marino 
45786d7f5d3SJohn Marino 	  /* Versions of the GNU binutils between 2.12 and 2.18 did
45886d7f5d3SJohn Marino 	     not handle objects with more than SHN_LORESERVE sections
45986d7f5d3SJohn Marino 	     correctly.  All large section indexes were offset by
46086d7f5d3SJohn Marino 	     0x100.  There is more information at
46186d7f5d3SJohn Marino 	     http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
46286d7f5d3SJohn Marino 	     Fortunately these object files are easy to detect, as the
46386d7f5d3SJohn Marino 	     GNU binutils always put the section header string table
46486d7f5d3SJohn Marino 	     near the end of the list of sections.  Thus if the
46586d7f5d3SJohn Marino 	     section header string table index is larger than the
46686d7f5d3SJohn Marino 	     number of sections, then we know we have to subtract
46786d7f5d3SJohn Marino 	     0x100 to get the real section index.  */
46886d7f5d3SJohn Marino 	  if (eor->shstrndx >= eor->shnum
46986d7f5d3SJohn Marino 	      && eor->shstrndx >= SHN_LORESERVE + 0x100)
47086d7f5d3SJohn Marino 	    eor->shstrndx -= 0x100;
47186d7f5d3SJohn Marino 	}
47286d7f5d3SJohn Marino     }
47386d7f5d3SJohn Marino 
47486d7f5d3SJohn Marino   if (eor->shstrndx >= eor->shnum)
47586d7f5d3SJohn Marino     {
47686d7f5d3SJohn Marino       *errmsg = "invalid ELF shstrndx >= shnum";
47786d7f5d3SJohn Marino       *err = 0;
47886d7f5d3SJohn Marino       XDELETE (eor);
47986d7f5d3SJohn Marino       return NULL;
48086d7f5d3SJohn Marino     }
48186d7f5d3SJohn Marino 
48286d7f5d3SJohn Marino   return (void *) eor;
48386d7f5d3SJohn Marino }
48486d7f5d3SJohn Marino 
48586d7f5d3SJohn Marino /* Find all sections in an ELF file.  */
48686d7f5d3SJohn Marino 
48786d7f5d3SJohn Marino static const char *
simple_object_elf_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,int * err)48886d7f5d3SJohn Marino simple_object_elf_find_sections (simple_object_read *sobj,
48986d7f5d3SJohn Marino 				 int (*pfn) (void *, const char *,
49086d7f5d3SJohn Marino 					     off_t offset, off_t length),
49186d7f5d3SJohn Marino 				 void *data,
49286d7f5d3SJohn Marino 				 int *err)
49386d7f5d3SJohn Marino {
49486d7f5d3SJohn Marino   struct simple_object_elf_read *eor =
49586d7f5d3SJohn Marino     (struct simple_object_elf_read *) sobj->data;
49686d7f5d3SJohn Marino   const struct elf_type_functions *type_functions = eor->type_functions;
49786d7f5d3SJohn Marino   unsigned char ei_class = eor->ei_class;
49886d7f5d3SJohn Marino   size_t shdr_size;
49986d7f5d3SJohn Marino   unsigned int shnum;
50086d7f5d3SJohn Marino   unsigned char *shdrs;
50186d7f5d3SJohn Marino   const char *errmsg;
50286d7f5d3SJohn Marino   unsigned char *shstrhdr;
50386d7f5d3SJohn Marino   size_t name_size;
50486d7f5d3SJohn Marino   off_t shstroff;
50586d7f5d3SJohn Marino   unsigned char *names;
50686d7f5d3SJohn Marino   unsigned int i;
50786d7f5d3SJohn Marino 
50886d7f5d3SJohn Marino   shdr_size = (ei_class == ELFCLASS32
50986d7f5d3SJohn Marino 	       ? sizeof (Elf32_External_Shdr)
51086d7f5d3SJohn Marino 	       : sizeof (Elf64_External_Shdr));
51186d7f5d3SJohn Marino 
51286d7f5d3SJohn Marino   /* Read the section headers.  We skip section 0, which is not a
51386d7f5d3SJohn Marino      useful section.  */
51486d7f5d3SJohn Marino 
51586d7f5d3SJohn Marino   shnum = eor->shnum;
51686d7f5d3SJohn Marino   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
51786d7f5d3SJohn Marino 
51886d7f5d3SJohn Marino   if (!simple_object_internal_read (sobj->descriptor,
51986d7f5d3SJohn Marino 				    sobj->offset + eor->shoff + shdr_size,
52086d7f5d3SJohn Marino 				    shdrs,
52186d7f5d3SJohn Marino 				    shdr_size * (shnum - 1),
52286d7f5d3SJohn Marino 				    &errmsg, err))
52386d7f5d3SJohn Marino     {
52486d7f5d3SJohn Marino       XDELETEVEC (shdrs);
52586d7f5d3SJohn Marino       return errmsg;
52686d7f5d3SJohn Marino     }
52786d7f5d3SJohn Marino 
52886d7f5d3SJohn Marino   /* Read the section names.  */
52986d7f5d3SJohn Marino 
53086d7f5d3SJohn Marino   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
53186d7f5d3SJohn Marino   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
53286d7f5d3SJohn Marino 			       shstrhdr, sh_size, Elf_Addr);
53386d7f5d3SJohn Marino   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
53486d7f5d3SJohn Marino 			      shstrhdr, sh_offset, Elf_Addr);
53586d7f5d3SJohn Marino   names = XNEWVEC (unsigned char, name_size);
53686d7f5d3SJohn Marino   if (!simple_object_internal_read (sobj->descriptor,
53786d7f5d3SJohn Marino 				    sobj->offset + shstroff,
53886d7f5d3SJohn Marino 				    names, name_size, &errmsg, err))
53986d7f5d3SJohn Marino     {
54086d7f5d3SJohn Marino       XDELETEVEC (names);
54186d7f5d3SJohn Marino       XDELETEVEC (shdrs);
54286d7f5d3SJohn Marino       return errmsg;
54386d7f5d3SJohn Marino     }
54486d7f5d3SJohn Marino 
54586d7f5d3SJohn Marino   for (i = 1; i < shnum; ++i)
54686d7f5d3SJohn Marino     {
54786d7f5d3SJohn Marino       unsigned char *shdr;
54886d7f5d3SJohn Marino       unsigned int sh_name;
54986d7f5d3SJohn Marino       const char *name;
55086d7f5d3SJohn Marino       off_t offset;
55186d7f5d3SJohn Marino       off_t length;
55286d7f5d3SJohn Marino 
55386d7f5d3SJohn Marino       shdr = shdrs + (i - 1) * shdr_size;
55486d7f5d3SJohn Marino       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
55586d7f5d3SJohn Marino 				 shdr, sh_name, Elf_Word);
55686d7f5d3SJohn Marino       if (sh_name >= name_size)
55786d7f5d3SJohn Marino 	{
55886d7f5d3SJohn Marino 	  *err = 0;
55986d7f5d3SJohn Marino 	  XDELETEVEC (names);
56086d7f5d3SJohn Marino 	  XDELETEVEC (shdrs);
56186d7f5d3SJohn Marino 	  return "ELF section name out of range";
56286d7f5d3SJohn Marino 	}
56386d7f5d3SJohn Marino 
56486d7f5d3SJohn Marino       name = (const char *) names + sh_name;
56586d7f5d3SJohn Marino       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
56686d7f5d3SJohn Marino 				shdr, sh_offset, Elf_Addr);
56786d7f5d3SJohn Marino       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
56886d7f5d3SJohn Marino 				shdr, sh_size, Elf_Addr);
56986d7f5d3SJohn Marino 
57086d7f5d3SJohn Marino       if (!(*pfn) (data, name, offset, length))
57186d7f5d3SJohn Marino 	break;
57286d7f5d3SJohn Marino     }
57386d7f5d3SJohn Marino 
57486d7f5d3SJohn Marino   XDELETEVEC (names);
57586d7f5d3SJohn Marino   XDELETEVEC (shdrs);
57686d7f5d3SJohn Marino 
57786d7f5d3SJohn Marino   return NULL;
57886d7f5d3SJohn Marino }
57986d7f5d3SJohn Marino 
58086d7f5d3SJohn Marino /* Fetch the attributes for an simple_object_read.  */
58186d7f5d3SJohn Marino 
58286d7f5d3SJohn Marino static void *
simple_object_elf_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)58386d7f5d3SJohn Marino simple_object_elf_fetch_attributes (simple_object_read *sobj,
58486d7f5d3SJohn Marino 				    const char **errmsg ATTRIBUTE_UNUSED,
58586d7f5d3SJohn Marino 				    int *err ATTRIBUTE_UNUSED)
58686d7f5d3SJohn Marino {
58786d7f5d3SJohn Marino   struct simple_object_elf_read *eor =
58886d7f5d3SJohn Marino     (struct simple_object_elf_read *) sobj->data;
58986d7f5d3SJohn Marino   struct simple_object_elf_attributes *ret;
59086d7f5d3SJohn Marino 
59186d7f5d3SJohn Marino   ret = XNEW (struct simple_object_elf_attributes);
59286d7f5d3SJohn Marino   ret->type_functions = eor->type_functions;
59386d7f5d3SJohn Marino   ret->ei_data = eor->ei_data;
59486d7f5d3SJohn Marino   ret->ei_class = eor->ei_class;
59586d7f5d3SJohn Marino   ret->ei_osabi = eor->ei_osabi;
59686d7f5d3SJohn Marino   ret->machine = eor->machine;
59786d7f5d3SJohn Marino   ret->flags = eor->flags;
59886d7f5d3SJohn Marino   return ret;
59986d7f5d3SJohn Marino }
60086d7f5d3SJohn Marino 
60186d7f5d3SJohn Marino /* Release the privata data for an simple_object_read.  */
60286d7f5d3SJohn Marino 
60386d7f5d3SJohn Marino static void
simple_object_elf_release_read(void * data)60486d7f5d3SJohn Marino simple_object_elf_release_read (void *data)
60586d7f5d3SJohn Marino {
60686d7f5d3SJohn Marino   XDELETE (data);
60786d7f5d3SJohn Marino }
60886d7f5d3SJohn Marino 
60986d7f5d3SJohn Marino /* Compare two attributes structures.  */
61086d7f5d3SJohn Marino 
61186d7f5d3SJohn Marino static const char *
simple_object_elf_attributes_merge(void * todata,void * fromdata,int * err)61286d7f5d3SJohn Marino simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
61386d7f5d3SJohn Marino {
61486d7f5d3SJohn Marino   struct simple_object_elf_attributes *to =
61586d7f5d3SJohn Marino     (struct simple_object_elf_attributes *) todata;
61686d7f5d3SJohn Marino   struct simple_object_elf_attributes *from =
61786d7f5d3SJohn Marino     (struct simple_object_elf_attributes *) fromdata;
61886d7f5d3SJohn Marino 
61986d7f5d3SJohn Marino   if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
62086d7f5d3SJohn Marino     {
62186d7f5d3SJohn Marino       *err = 0;
62286d7f5d3SJohn Marino       return "ELF object format mismatch";
62386d7f5d3SJohn Marino     }
62486d7f5d3SJohn Marino 
62586d7f5d3SJohn Marino   if (to->machine != from->machine)
62686d7f5d3SJohn Marino     {
62786d7f5d3SJohn Marino       int ok;
62886d7f5d3SJohn Marino 
62986d7f5d3SJohn Marino       /* EM_SPARC and EM_SPARC32PLUS are compatible and force an
63086d7f5d3SJohn Marino 	 output of EM_SPARC32PLUS.  */
63186d7f5d3SJohn Marino       ok = 0;
63286d7f5d3SJohn Marino       switch (to->machine)
63386d7f5d3SJohn Marino 	{
63486d7f5d3SJohn Marino 	case EM_SPARC:
63586d7f5d3SJohn Marino 	  if (from->machine == EM_SPARC32PLUS)
63686d7f5d3SJohn Marino 	    {
63786d7f5d3SJohn Marino 	      to->machine = from->machine;
63886d7f5d3SJohn Marino 	      ok = 1;
63986d7f5d3SJohn Marino 	    }
64086d7f5d3SJohn Marino 	  break;
64186d7f5d3SJohn Marino 
64286d7f5d3SJohn Marino 	case EM_SPARC32PLUS:
64386d7f5d3SJohn Marino 	  if (from->machine == EM_SPARC)
64486d7f5d3SJohn Marino 	    ok = 1;
64586d7f5d3SJohn Marino 	  break;
64686d7f5d3SJohn Marino 
64786d7f5d3SJohn Marino 	default:
64886d7f5d3SJohn Marino 	  break;
64986d7f5d3SJohn Marino 	}
65086d7f5d3SJohn Marino 
65186d7f5d3SJohn Marino       if (!ok)
65286d7f5d3SJohn Marino 	{
65386d7f5d3SJohn Marino 	  *err = 0;
65486d7f5d3SJohn Marino 	  return "ELF machine number mismatch";
65586d7f5d3SJohn Marino 	}
65686d7f5d3SJohn Marino     }
65786d7f5d3SJohn Marino 
65886d7f5d3SJohn Marino   return NULL;
65986d7f5d3SJohn Marino }
66086d7f5d3SJohn Marino 
66186d7f5d3SJohn Marino /* Release the private data for an attributes structure.  */
66286d7f5d3SJohn Marino 
66386d7f5d3SJohn Marino static void
simple_object_elf_release_attributes(void * data)66486d7f5d3SJohn Marino simple_object_elf_release_attributes (void *data)
66586d7f5d3SJohn Marino {
66686d7f5d3SJohn Marino   XDELETE (data);
66786d7f5d3SJohn Marino }
66886d7f5d3SJohn Marino 
66986d7f5d3SJohn Marino /* Prepare to write out a file.  */
67086d7f5d3SJohn Marino 
67186d7f5d3SJohn Marino static void *
simple_object_elf_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)67286d7f5d3SJohn Marino simple_object_elf_start_write (void *attributes_data,
67386d7f5d3SJohn Marino 			       const char **errmsg ATTRIBUTE_UNUSED,
67486d7f5d3SJohn Marino 			       int *err ATTRIBUTE_UNUSED)
67586d7f5d3SJohn Marino {
67686d7f5d3SJohn Marino   struct simple_object_elf_attributes *attrs =
67786d7f5d3SJohn Marino     (struct simple_object_elf_attributes *) attributes_data;
67886d7f5d3SJohn Marino   struct simple_object_elf_attributes *ret;
67986d7f5d3SJohn Marino 
68086d7f5d3SJohn Marino   /* We're just going to record the attributes, but we need to make a
68186d7f5d3SJohn Marino      copy because the user may delete them.  */
68286d7f5d3SJohn Marino   ret = XNEW (struct simple_object_elf_attributes);
68386d7f5d3SJohn Marino   *ret = *attrs;
68486d7f5d3SJohn Marino   return ret;
68586d7f5d3SJohn Marino }
68686d7f5d3SJohn Marino 
68786d7f5d3SJohn Marino /* Write out an ELF ehdr.  */
68886d7f5d3SJohn Marino 
68986d7f5d3SJohn Marino static int
simple_object_elf_write_ehdr(simple_object_write * sobj,int descriptor,const char ** errmsg,int * err)69086d7f5d3SJohn Marino simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
69186d7f5d3SJohn Marino 			      const char **errmsg, int *err)
69286d7f5d3SJohn Marino {
69386d7f5d3SJohn Marino   struct simple_object_elf_attributes *attrs =
69486d7f5d3SJohn Marino     (struct simple_object_elf_attributes *) sobj->data;
69586d7f5d3SJohn Marino   const struct elf_type_functions* fns;
69686d7f5d3SJohn Marino   unsigned char cl;
69786d7f5d3SJohn Marino   size_t ehdr_size;
69886d7f5d3SJohn Marino   unsigned char buf[sizeof (Elf64_External_Ehdr)];
69986d7f5d3SJohn Marino   simple_object_write_section *section;
70086d7f5d3SJohn Marino   unsigned int shnum;
70186d7f5d3SJohn Marino 
70286d7f5d3SJohn Marino   fns = attrs->type_functions;
70386d7f5d3SJohn Marino   cl = attrs->ei_class;
70486d7f5d3SJohn Marino 
70586d7f5d3SJohn Marino   shnum = 0;
70686d7f5d3SJohn Marino   for (section = sobj->sections; section != NULL; section = section->next)
70786d7f5d3SJohn Marino     ++shnum;
70886d7f5d3SJohn Marino   if (shnum > 0)
70986d7f5d3SJohn Marino     {
71086d7f5d3SJohn Marino       /* Add a section header for the dummy section and one for
71186d7f5d3SJohn Marino 	 .shstrtab.  */
71286d7f5d3SJohn Marino       shnum += 2;
71386d7f5d3SJohn Marino     }
71486d7f5d3SJohn Marino 
71586d7f5d3SJohn Marino   ehdr_size = (cl == ELFCLASS32
71686d7f5d3SJohn Marino 	       ? sizeof (Elf32_External_Ehdr)
71786d7f5d3SJohn Marino 	       : sizeof (Elf64_External_Ehdr));
71886d7f5d3SJohn Marino   memset (buf, 0, sizeof (Elf64_External_Ehdr));
71986d7f5d3SJohn Marino 
72086d7f5d3SJohn Marino   buf[EI_MAG0] = ELFMAG0;
72186d7f5d3SJohn Marino   buf[EI_MAG1] = ELFMAG1;
72286d7f5d3SJohn Marino   buf[EI_MAG2] = ELFMAG2;
72386d7f5d3SJohn Marino   buf[EI_MAG3] = ELFMAG3;
72486d7f5d3SJohn Marino   buf[EI_CLASS] = cl;
72586d7f5d3SJohn Marino   buf[EI_DATA] = attrs->ei_data;
72686d7f5d3SJohn Marino   buf[EI_VERSION] = EV_CURRENT;
72786d7f5d3SJohn Marino   buf[EI_OSABI] = attrs->ei_osabi;
72886d7f5d3SJohn Marino 
72986d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL);
73086d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine);
73186d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT);
73286d7f5d3SJohn Marino   /* e_entry left as zero.  */
73386d7f5d3SJohn Marino   /* e_phoff left as zero.  */
73486d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size);
73586d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags);
73686d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size);
73786d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half,
73886d7f5d3SJohn Marino 		 (cl == ELFCLASS32
73986d7f5d3SJohn Marino 		  ? sizeof (Elf32_External_Phdr)
74086d7f5d3SJohn Marino 		  : sizeof (Elf64_External_Phdr)));
74186d7f5d3SJohn Marino   /* e_phnum left as zero.  */
74286d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half,
74386d7f5d3SJohn Marino 		 (cl == ELFCLASS32
74486d7f5d3SJohn Marino 		  ? sizeof (Elf32_External_Shdr)
74586d7f5d3SJohn Marino 		  : sizeof (Elf64_External_Shdr)));
74686d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum);
74786d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half,
74886d7f5d3SJohn Marino 		 shnum == 0 ? 0 : shnum - 1);
74986d7f5d3SJohn Marino 
75086d7f5d3SJohn Marino   return simple_object_internal_write (descriptor, 0, buf, ehdr_size,
75186d7f5d3SJohn Marino 				       errmsg, err);
75286d7f5d3SJohn Marino }
75386d7f5d3SJohn Marino 
75486d7f5d3SJohn Marino /* Write out an ELF shdr.  */
75586d7f5d3SJohn Marino 
75686d7f5d3SJohn Marino static int
simple_object_elf_write_shdr(simple_object_write * sobj,int descriptor,off_t offset,unsigned int sh_name,unsigned int sh_type,unsigned int sh_flags,unsigned int sh_offset,unsigned int sh_size,unsigned int sh_addralign,const char ** errmsg,int * err)75786d7f5d3SJohn Marino simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
75886d7f5d3SJohn Marino 			      off_t offset, unsigned int sh_name,
75986d7f5d3SJohn Marino 			      unsigned int sh_type, unsigned int sh_flags,
76086d7f5d3SJohn Marino 			      unsigned int sh_offset, unsigned int sh_size,
76186d7f5d3SJohn Marino 			      unsigned int sh_addralign, const char **errmsg,
76286d7f5d3SJohn Marino 			      int *err)
76386d7f5d3SJohn Marino {
76486d7f5d3SJohn Marino   struct simple_object_elf_attributes *attrs =
76586d7f5d3SJohn Marino     (struct simple_object_elf_attributes *) sobj->data;
76686d7f5d3SJohn Marino   const struct elf_type_functions* fns;
76786d7f5d3SJohn Marino   unsigned char cl;
76886d7f5d3SJohn Marino   size_t shdr_size;
76986d7f5d3SJohn Marino   unsigned char buf[sizeof (Elf64_External_Shdr)];
77086d7f5d3SJohn Marino 
77186d7f5d3SJohn Marino   fns = attrs->type_functions;
77286d7f5d3SJohn Marino   cl = attrs->ei_class;
77386d7f5d3SJohn Marino 
77486d7f5d3SJohn Marino   shdr_size = (cl == ELFCLASS32
77586d7f5d3SJohn Marino 	       ? sizeof (Elf32_External_Shdr)
77686d7f5d3SJohn Marino 	       : sizeof (Elf64_External_Shdr));
77786d7f5d3SJohn Marino   memset (buf, 0, sizeof (Elf64_External_Shdr));
77886d7f5d3SJohn Marino 
77986d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
78086d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
78186d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
78286d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
78386d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
78486d7f5d3SJohn Marino   /* sh_link left as zero.  */
78586d7f5d3SJohn Marino   /* sh_info left as zero.  */
78686d7f5d3SJohn Marino   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
78786d7f5d3SJohn Marino   /* sh_entsize left as zero.  */
78886d7f5d3SJohn Marino 
78986d7f5d3SJohn Marino   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
79086d7f5d3SJohn Marino 				       errmsg, err);
79186d7f5d3SJohn Marino }
79286d7f5d3SJohn Marino 
79386d7f5d3SJohn Marino /* Write out a complete ELF file.
79486d7f5d3SJohn Marino    Ehdr
79586d7f5d3SJohn Marino    initial dummy Shdr
79686d7f5d3SJohn Marino    user-created Shdrs
79786d7f5d3SJohn Marino    .shstrtab Shdr
79886d7f5d3SJohn Marino    user-created section data
79986d7f5d3SJohn Marino    .shstrtab data  */
80086d7f5d3SJohn Marino 
80186d7f5d3SJohn Marino static const char *
simple_object_elf_write_to_file(simple_object_write * sobj,int descriptor,int * err)80286d7f5d3SJohn Marino simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
80386d7f5d3SJohn Marino 				 int *err)
80486d7f5d3SJohn Marino {
80586d7f5d3SJohn Marino   struct simple_object_elf_attributes *attrs =
80686d7f5d3SJohn Marino     (struct simple_object_elf_attributes *) sobj->data;
80786d7f5d3SJohn Marino   unsigned char cl;
80886d7f5d3SJohn Marino   size_t ehdr_size;
80986d7f5d3SJohn Marino   size_t shdr_size;
81086d7f5d3SJohn Marino   const char *errmsg;
81186d7f5d3SJohn Marino   simple_object_write_section *section;
81286d7f5d3SJohn Marino   unsigned int shnum;
81386d7f5d3SJohn Marino   size_t shdr_offset;
81486d7f5d3SJohn Marino   size_t sh_offset;
81586d7f5d3SJohn Marino   size_t sh_name;
81686d7f5d3SJohn Marino   unsigned char zero;
81786d7f5d3SJohn Marino 
81886d7f5d3SJohn Marino   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
81986d7f5d3SJohn Marino     return errmsg;
82086d7f5d3SJohn Marino 
82186d7f5d3SJohn Marino   cl = attrs->ei_class;
82286d7f5d3SJohn Marino   if (cl == ELFCLASS32)
82386d7f5d3SJohn Marino     {
82486d7f5d3SJohn Marino       ehdr_size = sizeof (Elf32_External_Ehdr);
82586d7f5d3SJohn Marino       shdr_size = sizeof (Elf32_External_Shdr);
82686d7f5d3SJohn Marino     }
82786d7f5d3SJohn Marino   else
82886d7f5d3SJohn Marino     {
82986d7f5d3SJohn Marino       ehdr_size = sizeof (Elf64_External_Ehdr);
83086d7f5d3SJohn Marino       shdr_size = sizeof (Elf64_External_Shdr);
83186d7f5d3SJohn Marino     }
83286d7f5d3SJohn Marino 
83386d7f5d3SJohn Marino   shnum = 0;
83486d7f5d3SJohn Marino   for (section = sobj->sections; section != NULL; section = section->next)
83586d7f5d3SJohn Marino     ++shnum;
83686d7f5d3SJohn Marino   if (shnum == 0)
83786d7f5d3SJohn Marino     return NULL;
83886d7f5d3SJohn Marino 
83986d7f5d3SJohn Marino   /* Add initial dummy Shdr and .shstrtab.  */
84086d7f5d3SJohn Marino   shnum += 2;
84186d7f5d3SJohn Marino 
84286d7f5d3SJohn Marino   shdr_offset = ehdr_size;
84386d7f5d3SJohn Marino   sh_offset = shdr_offset + shnum * shdr_size;
84486d7f5d3SJohn Marino 
84586d7f5d3SJohn Marino   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
84686d7f5d3SJohn Marino 				     0, 0, 0, 0, 0, 0, &errmsg, err))
84786d7f5d3SJohn Marino     return errmsg;
84886d7f5d3SJohn Marino 
84986d7f5d3SJohn Marino   shdr_offset += shdr_size;
85086d7f5d3SJohn Marino 
85186d7f5d3SJohn Marino   sh_name = 1;
85286d7f5d3SJohn Marino   for (section = sobj->sections; section != NULL; section = section->next)
85386d7f5d3SJohn Marino     {
85486d7f5d3SJohn Marino       size_t mask;
85586d7f5d3SJohn Marino       size_t new_sh_offset;
85686d7f5d3SJohn Marino       size_t sh_size;
85786d7f5d3SJohn Marino       struct simple_object_write_section_buffer *buffer;
85886d7f5d3SJohn Marino 
85986d7f5d3SJohn Marino       mask = (1U << section->align) - 1;
86086d7f5d3SJohn Marino       new_sh_offset = sh_offset + mask;
86186d7f5d3SJohn Marino       new_sh_offset &= ~ mask;
86286d7f5d3SJohn Marino       while (new_sh_offset > sh_offset)
86386d7f5d3SJohn Marino 	{
86486d7f5d3SJohn Marino 	  unsigned char zeroes[16];
86586d7f5d3SJohn Marino 	  size_t write;
86686d7f5d3SJohn Marino 
86786d7f5d3SJohn Marino 	  memset (zeroes, 0, sizeof zeroes);
86886d7f5d3SJohn Marino 	  write = new_sh_offset - sh_offset;
86986d7f5d3SJohn Marino 	  if (write > sizeof zeroes)
87086d7f5d3SJohn Marino 	    write = sizeof zeroes;
87186d7f5d3SJohn Marino 	  if (!simple_object_internal_write (descriptor, sh_offset, zeroes,
87286d7f5d3SJohn Marino 					     write, &errmsg, err))
87386d7f5d3SJohn Marino 	    return errmsg;
87486d7f5d3SJohn Marino 	  sh_offset += write;
87586d7f5d3SJohn Marino 	}
87686d7f5d3SJohn Marino 
87786d7f5d3SJohn Marino       sh_size = 0;
87886d7f5d3SJohn Marino       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
87986d7f5d3SJohn Marino 	{
88086d7f5d3SJohn Marino 	  if (!simple_object_internal_write (descriptor, sh_offset + sh_size,
88186d7f5d3SJohn Marino 					     ((const unsigned char *)
88286d7f5d3SJohn Marino 					      buffer->buffer),
88386d7f5d3SJohn Marino 					     buffer->size, &errmsg, err))
88486d7f5d3SJohn Marino 	    return errmsg;
88586d7f5d3SJohn Marino 	  sh_size += buffer->size;
88686d7f5d3SJohn Marino 	}
88786d7f5d3SJohn Marino 
88886d7f5d3SJohn Marino       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
88986d7f5d3SJohn Marino 					 sh_name, SHT_PROGBITS, 0, sh_offset,
89086d7f5d3SJohn Marino 					 sh_size, 1U << section->align,
89186d7f5d3SJohn Marino 					 &errmsg, err))
89286d7f5d3SJohn Marino 	return errmsg;
89386d7f5d3SJohn Marino 
89486d7f5d3SJohn Marino       shdr_offset += shdr_size;
89586d7f5d3SJohn Marino       sh_name += strlen (section->name) + 1;
89686d7f5d3SJohn Marino       sh_offset += sh_size;
89786d7f5d3SJohn Marino     }
89886d7f5d3SJohn Marino 
89986d7f5d3SJohn Marino   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
90086d7f5d3SJohn Marino 				     sh_name, SHT_STRTAB, 0, sh_offset,
90186d7f5d3SJohn Marino 				     sh_name + strlen (".shstrtab") + 1,
90286d7f5d3SJohn Marino 				     1, &errmsg, err))
90386d7f5d3SJohn Marino     return errmsg;
90486d7f5d3SJohn Marino 
90586d7f5d3SJohn Marino   /* .shstrtab has a leading zero byte.  */
90686d7f5d3SJohn Marino   zero = 0;
90786d7f5d3SJohn Marino   if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1,
90886d7f5d3SJohn Marino 				     &errmsg, err))
90986d7f5d3SJohn Marino     return errmsg;
91086d7f5d3SJohn Marino   ++sh_offset;
91186d7f5d3SJohn Marino 
91286d7f5d3SJohn Marino   for (section = sobj->sections; section != NULL; section = section->next)
91386d7f5d3SJohn Marino     {
91486d7f5d3SJohn Marino       size_t len;
91586d7f5d3SJohn Marino 
91686d7f5d3SJohn Marino       len = strlen (section->name) + 1;
91786d7f5d3SJohn Marino       if (!simple_object_internal_write (descriptor, sh_offset,
91886d7f5d3SJohn Marino 					 (const unsigned char *) section->name,
91986d7f5d3SJohn Marino 					 len, &errmsg, err))
92086d7f5d3SJohn Marino 	return errmsg;
92186d7f5d3SJohn Marino       sh_offset += len;
92286d7f5d3SJohn Marino     }
92386d7f5d3SJohn Marino 
92486d7f5d3SJohn Marino   if (!simple_object_internal_write (descriptor, sh_offset,
92586d7f5d3SJohn Marino 				     (const unsigned char *) ".shstrtab",
92686d7f5d3SJohn Marino 				     strlen (".shstrtab") + 1, &errmsg, err))
92786d7f5d3SJohn Marino     return errmsg;
92886d7f5d3SJohn Marino 
92986d7f5d3SJohn Marino   return NULL;
93086d7f5d3SJohn Marino }
93186d7f5d3SJohn Marino 
93286d7f5d3SJohn Marino /* Release the private data for an simple_object_write structure.  */
93386d7f5d3SJohn Marino 
93486d7f5d3SJohn Marino static void
simple_object_elf_release_write(void * data)93586d7f5d3SJohn Marino simple_object_elf_release_write (void *data)
93686d7f5d3SJohn Marino {
93786d7f5d3SJohn Marino   XDELETE (data);
93886d7f5d3SJohn Marino }
93986d7f5d3SJohn Marino 
94086d7f5d3SJohn Marino /* The ELF functions.  */
94186d7f5d3SJohn Marino 
94286d7f5d3SJohn Marino const struct simple_object_functions simple_object_elf_functions =
94386d7f5d3SJohn Marino {
94486d7f5d3SJohn Marino   simple_object_elf_match,
94586d7f5d3SJohn Marino   simple_object_elf_find_sections,
94686d7f5d3SJohn Marino   simple_object_elf_fetch_attributes,
94786d7f5d3SJohn Marino   simple_object_elf_release_read,
94886d7f5d3SJohn Marino   simple_object_elf_attributes_merge,
94986d7f5d3SJohn Marino   simple_object_elf_release_attributes,
95086d7f5d3SJohn Marino   simple_object_elf_start_write,
95186d7f5d3SJohn Marino   simple_object_elf_write_to_file,
95286d7f5d3SJohn Marino   simple_object_elf_release_write
95386d7f5d3SJohn Marino };
954