]> rtime.felk.cvut.cz Git - l4.git/blob - l4/tool/elf-patcher/elf-patcher.cc
23141719d2fbd7017595f8fa948a2ca80804dd8b
[l4.git] / l4 / tool / elf-patcher / elf-patcher.cc
1 #define _BSD_SOURCE
2
3 #include <sys/mman.h>
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <elf.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <endian.h>
14
15 template< typename T >
16 T host_to(int be, long long v, T &t)
17 {
18 #if __BYTE_ORDER == __LITTLE_ENDIAN
19   bool rot = be;
20 #else
21   bool rot = !be;
22 #endif
23   if (rot)
24     {
25       T _v = v;
26       for (unsigned i = 0; i < sizeof(T); ++i)
27         ((unsigned char*)&t)[i] = ((unsigned char *)&_v)[sizeof(T)-i-1];
28     }
29   else
30     t = v;
31
32   return t;
33 }
34
35 #define Elf(x) Elf32_ ## x
36 #include "elf-patcher.h"
37
38 #undef Elf
39 #define Elf(x) Elf64_ ## x
40 #include "elf-patcher.h"
41
42 static unsigned long long
43 get_param(const char *opt, int argc, const char *argv[])
44 {
45   size_t l = strlen(opt);
46   int i;
47   for (i = 2; i < argc; ++i)
48     {
49       if (strncmp(opt, argv[i], l) == 0)
50         {
51           if (strlen(argv[i]) >= l + 2)
52             return strtoll(argv[i] + l + 1, NULL, 0);
53           else
54             {
55               fprintf(stderr, "error parsing argument '%s'\n", opt);
56               return ~0ULL;
57             }
58         }
59     }
60   return ~0ULL;
61 }
62
63 static int
64 check_elf(void *_elf, const char *name)
65 {
66   Elf32_Ehdr *elf = (Elf32_Ehdr*)_elf;
67   if (memcmp(elf->e_ident, ELFMAG, sizeof(ELFMAG)-1) != 0)
68     {
69       fprintf(stderr, "'%s' is not an ELF binary\n", name);
70       return 1;
71     }
72   return 0;
73 }
74
75 static int
76 patch_phdrs(void *_elf, int argc, const char *argv[])
77 {
78   Elf32_Ehdr *elf = (Elf32_Ehdr*)_elf;
79   unsigned long long stack_addr, stack_size, kip_addr;
80
81   stack_addr = get_param("--stack_addr", argc, argv);
82   stack_size = get_param("--stack_size", argc, argv);
83   kip_addr   = get_param("--kip_addr"  , argc, argv);
84
85   if (stack_addr == ~0ULL || stack_size == ~0ULL || kip_addr == ~0ULL)
86     return 1;
87
88   if (elf->e_ident[EI_CLASS] == ELFCLASS64)
89     return Elf64_patch_phdrs(elf, stack_addr, stack_size, kip_addr);
90   else if (elf->e_ident[EI_CLASS] == ELFCLASS32)
91     return Elf32_patch_phdrs(elf, stack_addr, stack_size, kip_addr);
92   else
93     {
94       fprintf(stderr, "invalid elf class\n");
95       return 1;
96     }
97 }
98
99 static int
100 patch_shdrs(void *_elf, int argc, const char *argv[])
101 {
102   Elf32_Ehdr *elf = (Elf32_Ehdr*)_elf;
103   unsigned long long min_align = get_param("--min-section-align", argc, argv);
104
105   if (min_align == ~0ULL)
106     return 1;
107
108   if (elf->e_ident[EI_CLASS] == ELFCLASS64)
109     return Elf64_patch_shdrs(elf, min_align);
110   else if (elf->e_ident[EI_CLASS] == ELFCLASS32)
111     return Elf32_patch_shdrs(elf, min_align);
112   else
113     {
114       fprintf(stderr, "invalid elf class\n");
115       return 1;
116     }
117 }
118
119 int main(int argc, const char *argv[])
120 {
121   int victim;
122   struct stat victim_sb;
123   void *elf_addr;
124
125   if (argc < 2)
126     {
127       fprintf(stderr,"usage: %s <elf-binary> [--stack_addr=<addr> --stack_size=<size> --kip_addr=<addr>] [--min-section-align=value]\n", argv[0]);
128       return 1;
129     }
130
131   victim = open(argv[1], O_RDWR);
132   if (victim < 0)
133     {
134       fprintf(stderr, "could not open '%s':", argv[1]);
135       perror("");
136       return 1;
137     }
138
139   if (fstat(victim, &victim_sb) == -1)
140     {
141       fprintf(stderr, "could not get size of '%s':", argv[1]);
142       perror("");
143       return 1;
144     }
145
146   elf_addr = mmap(NULL, victim_sb.st_size, PROT_READ | PROT_WRITE,
147                   MAP_SHARED, victim, 0);
148
149   if (elf_addr == MAP_FAILED)
150     {
151       fprintf(stderr, "could not mmap '%s':", argv[1]);
152       perror("");
153       return 1;
154     }
155
156   if (check_elf(elf_addr, argv[1]))
157     return 1;
158
159   patch_phdrs(elf_addr, argc, argv);
160   patch_shdrs(elf_addr, argc, argv);
161
162   close(victim);
163   return 0;
164 }