16fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath/* Return number of program headers in the ELF file.
21ccdfb683ad6c7e59793136c3a657ddf131cafd1Mark Wielaard   Copyright (C) 2010, 2014, 2015 Red Hat, Inc.
3de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is part of elfutils.
46fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
5de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is free software; you can redistribute it and/or modify
6de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   it under the terms of either
76fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
8de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU Lesser General Public License as published by the Free
9de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 3 of the License, or (at
10de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
11de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
12de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or
13de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
14de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU General Public License as published by the Free
15de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 2 of the License, or (at
16de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
17de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
18de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or both in parallel, as here.
19de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
20de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   elfutils is distributed in the hope that it will be useful, but
216fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   WITHOUT ANY WARRANTY; without even the implied warranty of
226fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
236fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   General Public License for more details.
246fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
25de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   You should have received copies of the GNU General Public License and
26de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   the GNU Lesser General Public License along with this program.  If
27de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   not, see <http://www.gnu.org/licenses/>.  */
286fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
296fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath#ifdef HAVE_CONFIG_H
306fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath# include <config.h>
316fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath#endif
326fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
336fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath#include <assert.h>
346fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath#include <gelf.h>
356fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath#include <stddef.h>
366fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
376fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath#include "libelfP.h"
386fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
396fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
406fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrathint
41d8698e55cbe95e56c3a4cbd67c320048ea4f087aMark Wielaardinternal_function
421ccdfb683ad6c7e59793136c3a657ddf131cafd1Mark Wielaard__elf_getphdrnum_rdlock (Elf *elf, size_t *dst)
436fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath{
446fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath if (unlikely (elf->state.elf64.ehdr == NULL))
456fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   {
466fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath     /* Maybe no ELF header was created yet.  */
476fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath     __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
486fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath     return -1;
496fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   }
506fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
516fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath *dst = (elf->class == ELFCLASS32
526fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath	 ? elf->state.elf32.ehdr->e_phnum
536fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath	 : elf->state.elf64.ehdr->e_phnum);
546fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
556fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath if (*dst == PN_XNUM)
566fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   {
576fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath     const Elf_ScnList *const scns = (elf->class == ELFCLASS32
586fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath				      ? &elf->state.elf32.scns
596fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath				      : &elf->state.elf64.scns);
606fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
616fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath     /* If there are no section headers, perhaps this is really just 65536
626fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath	written without PN_XNUM support.  Either that or it's bad data.  */
636fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
64436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard     if (elf->class == ELFCLASS32)
65436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard       {
66436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard	 if (likely (scns->cnt > 0
67436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard		     && elf->state.elf32.scns.data[0].shdr.e32 != NULL))
68436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard	   *dst = scns->data[0].shdr.e32->sh_info;
69436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard       }
70436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard     else
71436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard       {
72436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard	 if (likely (scns->cnt > 0
73436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard		     && elf->state.elf64.scns.data[0].shdr.e64 != NULL))
74436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard	   *dst = scns->data[0].shdr.e64->sh_info;
75436275edd015ab6a6f8e164ee2292f74f03d2413Mark Wielaard       }
766fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath   }
776fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
786fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath return 0;
796fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath}
806fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
816fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrathint
82d8698e55cbe95e56c3a4cbd67c320048ea4f087aMark Wielaardinternal_function
831ccdfb683ad6c7e59793136c3a657ddf131cafd1Mark Wielaard__elf_getphdrnum_chk_rdlock (Elf *elf, size_t *dst)
846fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath{
85cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  int result = __elf_getphdrnum_rdlock (elf, dst);
862deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard
872deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  /* Do some sanity checking to make sure phnum and phoff are consistent.  */
882deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  Elf64_Off off = (elf->class == ELFCLASS32
892deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard		   ? elf->state.elf32.ehdr->e_phoff
902deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard		   : elf->state.elf64.ehdr->e_phoff);
912deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  if (unlikely (off == 0))
922deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    {
932deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard      *dst = 0;
94cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard      return result;
952deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    }
962deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard
972deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  if (unlikely (off >= elf->maximum_size))
982deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    {
992deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard      __libelf_seterrno (ELF_E_INVALID_DATA);
100cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard      return -1;
1012deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    }
1022deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard
1032deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  /* Check for too many sections.  */
1042deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  size_t phdr_size = (elf->class == ELFCLASS32
1052deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard		      ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr));
1062deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  if (unlikely (*dst > SIZE_MAX / phdr_size))
1072deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    {
1082deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard      __libelf_seterrno (ELF_E_INVALID_DATA);
109cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard      return -1;
1102deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    }
1112deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard
1122deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  /* Truncated file?  Don't return more than can be indexed.  */
1132deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard  if (unlikely (elf->maximum_size - off < *dst * phdr_size))
1142deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard    *dst = (elf->maximum_size - off) / phdr_size;
1152deeb7c51020df07d752107cdc6822d70ae1da4eMark Wielaard
116cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  return result;
117cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard}
118cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard
119cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaardint
1201ccdfb683ad6c7e59793136c3a657ddf131cafd1Mark Wielaardelf_getphdrnum (Elf *elf, size_t *dst)
121cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard{
122cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  int result;
123cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard
124cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  if (elf == NULL)
125cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard    return -1;
126cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard
127cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  if (unlikely (elf->kind != ELF_K_ELF))
128cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard    {
129cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard      __libelf_seterrno (ELF_E_INVALID_HANDLE);
130cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard      return -1;
131cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard    }
132cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard
133cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  rwlock_rdlock (elf->lock);
134cc62e378c292daaded19f1fe03681d63b7437ea0Mark Wielaard  result = __elf_getphdrnum_chk_rdlock (elf, dst);
1356fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath  rwlock_unlock (elf->lock);
1366fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath
1376fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath  return result;
1386fd3cd104adf4107aa64e1c1e84028b4ea0b3296Roland McGrath}
139