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