GPLv2 release
[centaur.git] / src / elfucli.c
1 /* This file is part of centaur.
2  *
3  * centaur is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License 2 as
5  * published by the Free Software Foundation.
6
7  * centaur is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11
12  * You should have received a copy of the GNU General Public License
13  * along with centaur.  If not, see <http://www.gnu.org/licenses/>.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <getopt.h>
20 #include <libelfu/libelfu.h>
21
22 #include "elfhandle.h"
23
24
25
26 static void printUsage(char *progname)
27 {
28   printf("Usage: %s -i <inputfile> [OPTIONS]\n", progname);
29   printf("\n"
30          "Options, executed in order given:\n"
31          "  -h, --help                     Print this help message\n"
32          "\n"
33          "  -i, --input         infile     Load new ELF file (must be first command)\n"
34          "\n"
35          "  -c, --check                    Do a few sanity checks and print any errors\n"
36          "  -d, --dump                     Dump current model state (debug only)\n"
37          "      --reladd        obj.o      Insert object file contents\n"
38          "      --detour        from,to    Write a jump to <to> at <from>\n"
39          "  -o, --output        outfile    Where to write the modified ELF file to\n"
40          "\n");
41 }
42
43
44
45
46 int main(int argc, char **argv)
47 {
48   ELFHandles hIn = { 0 };
49   int exitval = EXIT_SUCCESS;
50   char *progname = argv[0];
51   int c;
52   int option_index = 0;
53   ElfuElf *me = NULL;
54
55   static struct option long_options[] = {
56     {"help", 0, 0, 'h'},
57     {"check", 0, 0, 'c'},
58     {"dump", 0, 0, 'd'},
59     {"input", 1, 0, 'i'},
60     {"output", 1, 0, 'o'},
61     {"reladd", 1, 0, 10001},
62     {"detour", 1, 0, 10002},
63     {NULL, 0, NULL, 0}
64   };
65
66
67   if (argc < 3) {
68     printUsage(progname);
69     goto EXIT;
70   }
71
72
73   /* Is libelf alive and well? */
74   if (elf_version(EV_CURRENT) == EV_NONE) {
75     fprintf(stderr, "libelf init error: %s\n", elf_errmsg(-1));
76   }
77
78
79   /* Parse and and execute user commands */
80   while ((c = getopt_long(argc, argv, "hcdi:o:",
81                           long_options, &option_index)) != -1) {
82     switch (c) {
83       case 'h':
84         printUsage(progname);
85         goto EXIT;
86       case 'c':
87         if (!me) {
88           goto ERR_NO_INPUT;
89         } else {
90           printf("Checking model validity...\n");
91           elfu_mCheck(me);
92         }
93         break;
94       case 'd':
95         if (!me) {
96           goto ERR_NO_INPUT;
97         } else {
98           elfu_mDumpElf(me);
99         }
100         break;
101       case 'i':
102         if (me) {
103           elfu_mElfDestroy(me);
104         }
105
106         printf("Opening input file %s.\n", optarg);
107         openElf(&hIn, optarg, ELF_C_READ);
108         if (!hIn.e) {
109           printf("Error: Failed to open input file. Aborting.\n");
110           exitval = EXIT_FAILURE;
111           goto EXIT;
112         }
113
114         me = elfu_mFromElf(hIn.e);
115         closeElf(&hIn);
116
117         if (!me) {
118           printf("Error: Failed to load model, aborting.\n");
119           goto EXIT;
120         }
121         break;
122       case 'o':
123         if (!me) {
124           goto ERR_NO_INPUT;
125         } else {
126           ELFHandles hOut = { 0 };
127
128           printf("Writing modified file to %s.\n", optarg);
129
130           openElf(&hOut, optarg, ELF_C_WRITE);
131           if (!hOut.e) {
132             printf("Failed to open output file. Aborting.\n");
133             closeElf(&hOut);
134             exitval = EXIT_FAILURE;
135             goto EXIT;
136           }
137
138           elfu_mToElf(me, hOut.e);
139
140           if (elf_update(hOut.e, ELF_C_WRITE) < 0) {
141             fprintf(stderr, "elf_update() failed: %s\n", elf_errmsg(-1));
142           }
143           closeElf(&hOut);
144         }
145         break;
146       case 10001:
147         if (!me) {
148           goto ERR_NO_INPUT;
149         } else {
150           ELFHandles hRel = { 0 };
151           ElfuElf *mrel = NULL;
152
153           openElf(&hRel, optarg, ELF_C_READ);
154           if (!hRel.e) {
155             printf("--reladd: Failed to open file for --reladd, aborting.\n");
156             closeElf(&hRel);
157             goto ERR;
158           }
159
160           mrel = elfu_mFromElf(hRel.e);
161           closeElf(&hRel);
162           if (!mrel) {
163             printf("--reladd: Failed to load model for --reladd, aborting.\n");
164             goto ERR;
165           } else {
166             printf("--reladd: Injecting %s...\n", optarg);
167             if (elfu_mCheck(mrel)) {
168               printf("--reladd: Check for input file failed.\n");
169               elfu_mElfDestroy(mrel);
170               goto ERR;
171             }
172             if (elfu_mReladd(me, mrel)) {
173               printf("--reladd: Failed.\n");
174               elfu_mElfDestroy(mrel);
175               goto ERR;
176             }
177             printf("--reladd: Injected %s.\n", optarg);
178             elfu_mElfDestroy(mrel);
179           }
180         }
181         break;
182       case 10002:
183         if (!me) {
184           goto ERR_NO_INPUT;
185         } else {
186           GElf_Addr from;
187           GElf_Addr to;
188           char *second;
189
190           strtok_r(optarg, ",", &second);
191           printf("--detour: From '%s' to '%s'\n", optarg, second);
192
193
194           from = strtoul(optarg, NULL, 0);
195           if (from == 0) {
196             from = elfu_mSymtabLookupAddrByName(me, me->symtab, optarg);
197           }
198           if (from == 0) {
199             printf("--detour: Cannot parse argument 1, aborting.\n");
200             goto ERR;
201           }
202           printf("--detour: From %x\n", (unsigned)from);
203
204           to = strtoul(second, NULL, 0);
205           if (to == 0) {
206             to = elfu_mSymtabLookupAddrByName(me, me->symtab, second);
207           }
208           if (to == 0) {
209             printf("--detour: Cannot parse argument 2, aborting.\n");
210             goto ERR;
211           }
212           printf("--detour: To %x\n", (unsigned)to);
213
214           elfu_mDetour(me, from, to);
215         }
216         break;
217       case '?':
218       default:
219         printUsage(progname);
220         goto EXIT;
221     }
222   }
223
224   while (optind < argc) {
225     optind++;
226   }
227
228
229
230 EXIT:
231   if (me) {
232     elfu_mElfDestroy(me);
233   }
234
235   if (hIn.e) {
236     closeElf(&hIn);
237   }
238
239   return (exitval);
240
241
242 ERR_NO_INPUT:
243   printf("Error: No input file opened. Aborting.\n");
244
245 ERR:
246   exitval = EXIT_FAILURE;
247   goto EXIT;
248 }