1 /* Copyright (C) 1999-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
18 #include <elf-read-prop.h>
20 /* This code is a heavily simplified version of the readelf program
21 that's part of the current binutils development version. For architectures
22 which need to handle both 32bit and 64bit ELF libraries, this file is
23 included twice for each arch size. */
25 /* check_ptr checks that a pointer is in the mmaped file and doesn't
28 #define check_ptr(ptr) \
31 if ((void *)(ptr) < file_contents \
32 || (void *)(ptr) > (file_contents+file_length)) \
34 error (0, 0, _("file %s is truncated\n"), file_name); \
40 /* Returns 0 if everything is ok, != 0 in case of error. */
42 process_elf_file (const char *file_name
, const char *lib
, int *flag
,
43 unsigned int *osversion
, unsigned int *isa_level
,
44 char **soname
, void *file_contents
, size_t file_length
)
48 unsigned int dynamic_addr
;
50 char *program_interpreter
;
52 ElfW(Ehdr
) *elf_header
;
53 ElfW(Phdr
) *elf_pheader
, *segment
;
54 ElfW(Dyn
) *dynamic_segment
, *dyn_entry
;
55 char *dynamic_strings
;
57 elf_header
= (ElfW(Ehdr
) *) file_contents
;
60 if (elf_header
->e_ident
[EI_CLASS
] != ElfW (CLASS
))
64 if (elf_header
->e_ident
[EI_CLASS
] == ELFCLASS32
)
65 error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name
);
66 else if (elf_header
->e_ident
[EI_CLASS
] == ELFCLASS64
)
67 error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name
);
69 error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name
);
74 if (elf_header
->e_type
!= ET_DYN
)
76 error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name
,
81 /* Get information from elf program header. */
82 elf_pheader
= (ElfW(Phdr
) *) (elf_header
->e_phoff
+ file_contents
);
83 check_ptr (elf_pheader
);
85 /* The library is an elf library, now search for soname and
89 /* The default ISA level is 0. */
94 program_interpreter
= NULL
;
95 for (i
= 0, segment
= elf_pheader
;
96 i
< elf_header
->e_phnum
; i
++, segment
++)
100 switch (segment
->p_type
)
104 error (0, 0, _("more than one dynamic segment\n"));
106 dynamic_addr
= segment
->p_offset
;
107 dynamic_size
= segment
->p_filesz
;
111 program_interpreter
= (char *) (file_contents
+ segment
->p_offset
);
112 check_ptr (program_interpreter
);
114 /* Check if this is enough to classify the binary. */
115 for (j
= 0; j
< sizeof (interpreters
) / sizeof (interpreters
[0]);
117 if (strcmp (program_interpreter
, interpreters
[j
].soname
) == 0)
119 *flag
= interpreters
[j
].flag
;
125 if (!*osversion
&& segment
->p_filesz
>= 32 && segment
->p_align
>= 4)
127 ElfW(Word
) *abi_note
= (ElfW(Word
) *) (file_contents
128 + segment
->p_offset
);
129 ElfW(Addr
) size
= segment
->p_filesz
;
130 /* NB: Some PT_NOTE segment may have alignment value of 0
131 or 1. gABI specifies that PT_NOTE segments should be
132 aligned to 4 bytes in 32-bit objects and to 8 bytes in
133 64-bit objects. As a Linux extension, we also support
134 4 byte alignment in 64-bit objects. If p_align is less
135 than 4, we treate alignment as 4 bytes since some note
136 segments have 0 or 1 byte alignment. */
137 ElfW(Addr
) align
= segment
->p_align
;
140 else if (align
!= 4 && align
!= 8)
143 while (abi_note
[0] != 4 || abi_note
[1] != 16
145 || memcmp (abi_note
+ 3, "GNU", 4) != 0)
148 = ELF_NOTE_NEXT_OFFSET (abi_note
[0], abi_note
[1],
151 if (size
- 32 < note_size
|| note_size
== 0)
157 abi_note
= (void *) abi_note
+ note_size
;
163 *osversion
= ((abi_note
[4] << 24)
164 | ((abi_note
[5] & 0xff) << 16)
165 | ((abi_note
[6] & 0xff) << 8)
166 | (abi_note
[7] & 0xff));
170 case PT_GNU_PROPERTY
:
171 /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes
172 in 32-bit objects and to 8 bytes in 64-bit objects. Skip
173 notes with incorrect alignment. */
174 if (segment
->p_align
== (__ELF_NATIVE_CLASS
/ 8))
176 const ElfW(Nhdr
) *note
= (const void *) (file_contents
177 + segment
->p_offset
);
178 const ElfW(Addr
) size
= segment
->p_filesz
;
179 const ElfW(Addr
) align
= segment
->p_align
;
181 const ElfW(Addr
) start
= (ElfW(Addr
)) (uintptr_t) note
;
182 unsigned int last_type
= 0;
184 while ((ElfW(Addr
)) (uintptr_t) (note
+ 1) - start
< size
)
186 /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
187 if (note
->n_namesz
== 4
188 && note
->n_type
== NT_GNU_PROPERTY_TYPE_0
189 && memcmp (note
+ 1, "GNU", 4) == 0)
191 /* Check for invalid property. */
192 if (note
->n_descsz
< 8
193 || (note
->n_descsz
% sizeof (ElfW(Addr
))) != 0)
196 /* Start and end of property array. */
197 unsigned char *ptr
= (unsigned char *) (note
+ 1) + 4;
198 unsigned char *ptr_end
= ptr
+ note
->n_descsz
;
202 unsigned int type
= *(unsigned int *) ptr
;
203 unsigned int datasz
= *(unsigned int *) (ptr
+ 4);
205 /* Property type must be in ascending order. */
206 if (type
< last_type
)
210 if ((ptr
+ datasz
) > ptr_end
)
215 /* Target specific property processing.
217 false: Continue processing the properties.
218 true : Stop processing the properties.
220 if (read_gnu_property (isa_level
, type
,
224 /* Check the next property item. */
225 ptr
+= ALIGN_UP (datasz
, sizeof (ElfW(Addr
)));
227 while ((ptr_end
- ptr
) >= 8);
229 /* Only handle one NT_GNU_PROPERTY_TYPE_0. */
233 note
= ((const void *) note
234 + ELF_NOTE_NEXT_OFFSET (note
->n_namesz
,
248 /* Now we can read the dynamic sections. */
249 if (dynamic_size
== 0)
252 dynamic_segment
= (ElfW(Dyn
) *) (file_contents
+ dynamic_addr
);
253 check_ptr (dynamic_segment
);
255 /* Find the string table. */
256 dynamic_strings
= NULL
;
257 for (dyn_entry
= dynamic_segment
; dyn_entry
->d_tag
!= DT_NULL
;
260 check_ptr (dyn_entry
);
261 if (dyn_entry
->d_tag
== DT_STRTAB
)
263 /* Find the file offset of the segment containing the dynamic
265 ElfW(Off
) loadoff
= -1;
266 for (i
= 0, segment
= elf_pheader
;
267 i
< elf_header
->e_phnum
; i
++, segment
++)
269 if (segment
->p_type
== PT_LOAD
270 && dyn_entry
->d_un
.d_val
>= segment
->p_vaddr
271 && (dyn_entry
->d_un
.d_val
- segment
->p_vaddr
272 < segment
->p_filesz
))
274 loadoff
= segment
->p_vaddr
- segment
->p_offset
;
278 if (loadoff
== (ElfW(Off
)) -1)
284 dynamic_strings
= (char *) (file_contents
+ dyn_entry
->d_un
.d_val
286 check_ptr (dynamic_strings
);
291 if (dynamic_strings
== NULL
)
294 /* Now read the DT_NEEDED and DT_SONAME entries. */
295 for (dyn_entry
= dynamic_segment
; dyn_entry
->d_tag
!= DT_NULL
;
298 if (dyn_entry
->d_tag
== DT_NEEDED
|| dyn_entry
->d_tag
== DT_SONAME
)
300 char *name
= dynamic_strings
+ dyn_entry
->d_un
.d_val
;
303 if (dyn_entry
->d_tag
== DT_NEEDED
)
306 if (*flag
== FLAG_ELF
)
308 /* Check if this is enough to classify the binary. */
310 j
< sizeof (known_libs
) / sizeof (known_libs
[0]);
312 if (strcmp (name
, known_libs
[j
].soname
) == 0)
314 *flag
= known_libs
[j
].flag
;
320 else if (dyn_entry
->d_tag
== DT_SONAME
)
321 *soname
= xstrdup (name
);
323 /* Do we have everything we need? */
324 if (*soname
&& *flag
!= FLAG_ELF
)