File: phdrtab.c

package info (click to toggle)
elfkickers 3.2%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 752 kB
  • sloc: ansic: 8,648; makefile: 125
file content (134 lines) | stat: -rw-r--r-- 4,129 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* phdrtab.c: Reading the program segment header table.
 * Copyright (C) 1999,2011 by Brian Raiter <breadbox@muppetlabs.com>
 * License GPLv2+: GNU GPL version 2 or later.
 * This is free software; you are free to change and redistribute it.
 * There is NO WARRANTY, to the extent permitted by law.
 */
#include <string.h>
#include <elf.h>
#include "gen.h"
#include "readelf.h"
#include "pieces.h"
#include "address.h"
#include "dynamic.h"
#include "phdrtab.h"

/* Examines an entry in the program segment header table and uses this
 * information to identify one piece of the ELF image. If the entry
 * also indicates mapping of offsets to addresses, this is also
 * recorded. Finally, if the entry points to a dynamic table, the
 * table's contents are examined as well.
 */
static void dividesegment(Elf64_Phdr const *phdr)
{
    char const *str;
    int type, n;

    if (phdr->p_type == PT_NULL || phdr->p_filesz == 0)
        return;
    switch (phdr->p_type) {
      case PT_PHDR:	    type = P_PHDRTAB;  str = "~phdrs";	    break;
      case PT_DYNAMIC:	    type = P_DYNAMIC;  str = "~dynamic";    break;
      case PT_INTERP:	    type = P_STRINGS;  str = "~interp";	    break;
      case PT_NOTE:	    type = P_NOTE;     str = "~note";	    break;
#ifdef PT_GNU_EH_FRAME
      case PT_GNU_EH_FRAME: type = P_WORDS;    str = "~eh_frame";   break;
#endif
      case PT_LOAD:
        type = P_SECTION;
        if (phdr->p_type == PT_LOAD) {
	    if (phdr->p_flags & PF_X)
		str = "~text";
	    else if (phdr->p_flags & PF_W)
		str = "~data";
	    else if (phdr->p_flags & PF_R)
		str = "~rodata";
	    else
		str = "";
        }
        break;
      default:
        type = P_SECTION;
        str = "";
        break;
    }
    n = recordpiece(phdr->p_offset, phdr->p_filesz, type, str, phdr->p_align);
    if (phdr->p_memsz && str)
        recordaddress(phdr->p_vaddr, phdr->p_offset, phdr->p_memsz, str);
    if (type == P_DYNAMIC)
	hashdynamicsection(phdr->p_offset, phdr->p_filesz, n);
}

/* Reads the given section of the ELF image as a program segment
 * header table, and records the information contained therein.
 * Warnings are displayed if the table itself appears to be malformed
 * or incorrectly sized. If this is a 32-bit table, each entry is
 * translated into a 64-bit entry so that the dividesegment() function
 * doesn't have to understand both types.
 */
void dividesegments(long offset, int count, int entsize)
{
    Elf64_Phdr ph64;
    Elf32_Phdr ph32;
    void const *ptr;
    long size;
    int i;

    if (!offset || !count)
	return;

    if (!entsize) {
	warn("ignoring zero value for phentsize.");
	entsize = sizeof_elf(Phdr);
    } else if (entsize != sizeof_elf(Phdr)) {
	warn("program header table entry size: %d instead of %d.",
	    entsize, sizeof_elf(Phdr));
    }

    size = count * entsize;
    ptr = getptrto(offset, &size);
    if (size != count * entsize) {
	if (size == 0) {
	    warn("invalid program segment header table offset: %ld.", offset);
	    return;
	}
	warn("program header table extends %ld bytes past EOF.",
	     count * entsize - size);
    }

    recordpiece(offset, size, P_PHDRTAB, "phdrs", sizeof_elf(Addr));

    count = size / entsize;
    if (!count)
	return;

    for (i = 0 ; i < count ; ++i) {
	if (iself64()) {
	    if (entsize >= (int)sizeof(Elf64_Phdr)) {
		dividesegment((Elf64_Phdr const*)ptr + i);
	    } else {
		memcpy(&ph64, (Elf64_Phdr const*)ptr + i, entsize);
		memset((char*)&ph64 + entsize, 0, sizeof ph64 - entsize);
		dividesegment(&ph64);
	    }
	} else {
	    if (entsize >= (int)sizeof(Elf32_Phdr)) {
		memcpy(&ph32, (char const*)ptr + i * entsize, sizeof ph32);
	    } else {
		memcpy(&ph32, (char const*)ptr + i * entsize, entsize);
		memset((char*)&ph32 + entsize, 0, sizeof ph32 - entsize);
	    }
	    ph64.p_type = ph32.p_type;
	    ph64.p_flags = ph32.p_flags;
	    ph64.p_offset = ph32.p_offset;
	    ph64.p_vaddr = ph32.p_vaddr;
	    ph64.p_paddr = ph32.p_paddr;
	    ph64.p_filesz = ph32.p_filesz;
	    ph64.p_memsz = ph32.p_memsz;
	    ph64.p_align = ph32.p_align;
	    dividesegment(&ph64);
	}
    }

    dividedynsegments();
}