6
6
#include <subcmd/parse-options.h>
7
7
#include <string.h>
8
8
#include <stdlib.h>
9
+ #include <fcntl.h>
10
+ #include <unistd.h>
11
+ #include <sys/stat.h>
12
+ #include <sys/sendfile.h>
9
13
#include <objtool/builtin.h>
10
14
#include <objtool/objtool.h>
11
15
14
18
"error: objtool: " format "\n", \
15
19
##__VA_ARGS__)
16
20
21
+ const char * objname ;
22
+
17
23
struct opts opts ;
18
24
19
25
static const char * const check_usage [] = {
@@ -71,7 +77,7 @@ static const struct option check_options[] = {
71
77
OPT_BOOLEAN ('i' , "ibt" , & opts .ibt , "validate and annotate IBT" ),
72
78
OPT_BOOLEAN ('m' , "mcount" , & opts .mcount , "annotate mcount/fentry calls for ftrace" ),
73
79
OPT_BOOLEAN ('n' , "noinstr" , & opts .noinstr , "validate noinstr rules" ),
74
- OPT_BOOLEAN ('o' , "orc" , & opts .orc , "generate ORC metadata" ),
80
+ OPT_BOOLEAN (0 , "orc" , & opts .orc , "generate ORC metadata" ),
75
81
OPT_BOOLEAN ('r' , "retpoline" , & opts .retpoline , "validate and annotate retpoline usage" ),
76
82
OPT_BOOLEAN (0 , "rethunk" , & opts .rethunk , "validate and annotate rethunk usage" ),
77
83
OPT_BOOLEAN (0 , "unret" , & opts .unret , "validate entry unret placement" ),
@@ -84,15 +90,16 @@ static const struct option check_options[] = {
84
90
OPT_CALLBACK_OPTARG (0 , "dump" , NULL , NULL , "orc" , "dump metadata" , parse_dump ),
85
91
86
92
OPT_GROUP ("Options:" ),
87
- OPT_BOOLEAN (0 , "backtrace" , & opts .backtrace , "unwind on error" ),
88
- OPT_BOOLEAN (0 , "backup" , & opts .backup , "create .orig files before modification" ),
89
- OPT_BOOLEAN (0 , "dry-run" , & opts .dryrun , "don't write modifications" ),
90
- OPT_BOOLEAN (0 , "link" , & opts .link , "object is a linked object" ),
91
- OPT_BOOLEAN (0 , "module" , & opts .module , "object is part of a kernel module" ),
92
- OPT_BOOLEAN (0 , "mnop" , & opts .mnop , "nop out mcount call sites" ),
93
- OPT_BOOLEAN (0 , "no-unreachable" , & opts .no_unreachable , "skip 'unreachable instruction' warnings" ),
94
- OPT_BOOLEAN (0 , "sec-address" , & opts .sec_address , "print section addresses in warnings" ),
95
- OPT_BOOLEAN (0 , "stats" , & opts .stats , "print statistics" ),
93
+ OPT_BOOLEAN (0 , "backtrace" , & opts .backtrace , "unwind on error" ),
94
+ OPT_BOOLEAN (0 , "backup" , & opts .backup , "create .orig files before modification" ),
95
+ OPT_BOOLEAN (0 , "dry-run" , & opts .dryrun , "don't write modifications" ),
96
+ OPT_BOOLEAN (0 , "link" , & opts .link , "object is a linked object" ),
97
+ OPT_BOOLEAN (0 , "module" , & opts .module , "object is part of a kernel module" ),
98
+ OPT_BOOLEAN (0 , "mnop" , & opts .mnop , "nop out mcount call sites" ),
99
+ OPT_BOOLEAN (0 , "no-unreachable" , & opts .no_unreachable , "skip 'unreachable instruction' warnings" ),
100
+ OPT_STRING ('o' , "output" , & opts .output , "file" , "output file name" ),
101
+ OPT_BOOLEAN (0 , "sec-address" , & opts .sec_address , "print section addresses in warnings" ),
102
+ OPT_BOOLEAN (0 , "stats" , & opts .stats , "print statistics" ),
96
103
OPT_BOOLEAN ('v' , "verbose" , & opts .verbose , "verbose warnings" ),
97
104
98
105
OPT_END (),
@@ -178,24 +185,75 @@ static bool opts_valid(void)
178
185
return false;
179
186
}
180
187
188
+ static int copy_file (const char * src , const char * dst )
189
+ {
190
+ size_t to_copy , copied ;
191
+ int dst_fd , src_fd ;
192
+ struct stat stat ;
193
+ off_t offset = 0 ;
194
+
195
+ src_fd = open (src , O_RDONLY );
196
+ if (src_fd == -1 ) {
197
+ ERROR ("can't open '%s' for reading" , src );
198
+ return 1 ;
199
+ }
200
+
201
+ dst_fd = open (dst , O_WRONLY | O_CREAT | O_TRUNC );
202
+ if (dst_fd == -1 ) {
203
+ ERROR ("can't open '%s' for writing" , dst );
204
+ return 1 ;
205
+ }
206
+
207
+ if (fstat (src_fd , & stat ) == -1 ) {
208
+ perror ("fstat" );
209
+ return 1 ;
210
+ }
211
+
212
+ if (fchmod (dst_fd , stat .st_mode ) == -1 ) {
213
+ perror ("fchmod" );
214
+ return 1 ;
215
+ }
216
+
217
+ for (to_copy = stat .st_size ; to_copy > 0 ; to_copy -= copied ) {
218
+ copied = sendfile (dst_fd , src_fd , & offset , to_copy );
219
+ if (copied == -1 ) {
220
+ perror ("sendfile" );
221
+ return 1 ;
222
+ }
223
+ }
224
+
225
+ close (dst_fd );
226
+ close (src_fd );
227
+ return 0 ;
228
+ }
229
+
181
230
int objtool_run (int argc , const char * * argv )
182
231
{
183
- const char * objname ;
184
232
struct objtool_file * file ;
185
233
int ret ;
186
234
187
- argc = cmd_parse_options (argc , argv , check_usage );
188
- objname = argv [0 ];
235
+ cmd_parse_options (argc , argv , check_usage );
189
236
190
237
if (!opts_valid ())
191
238
return 1 ;
192
239
240
+ objname = argv [0 ];
241
+
193
242
if (opts .dump_orc )
194
243
return orc_dump (objname );
195
244
245
+ if (!opts .dryrun && opts .output ) {
246
+ /* copy original .o file to output file */
247
+ if (copy_file (objname , opts .output ))
248
+ return 1 ;
249
+
250
+ /* from here on, work directly on the output file */
251
+ objname = opts .output ;
252
+ }
253
+
196
254
file = objtool_open_read (objname );
197
255
if (!file )
198
- return 1 ;
256
+ goto err ;
199
257
200
258
if (!opts .link && has_multiple_files (file -> elf )) {
201
259
ERROR ("Linked object requires --link" );
@@ -204,10 +262,16 @@ int objtool_run(int argc, const char **argv)
204
262
205
263
ret = check (file );
206
264
if (ret )
207
- return ret ;
265
+ goto err ;
208
266
209
- if (file -> elf -> changed )
210
- return elf_write ( file -> elf ) ;
267
+ if (! opts . dryrun && file -> elf -> changed && elf_write ( file -> elf ) )
268
+ goto err ;
211
269
212
270
return 0 ;
271
+
272
+ err :
273
+ if (opts .output )
274
+ unlink (opts .output );
275
+
276
+ return 1 ;
213
277
}
0 commit comments