66#include <subcmd/parse-options.h>
77#include <string.h>
88#include <stdlib.h>
9+ #include <fcntl.h>
10+ #include <unistd.h>
11+ #include <sys/stat.h>
12+ #include <sys/sendfile.h>
913#include <objtool/builtin.h>
1014#include <objtool/objtool.h>
1115
1418 "error: objtool: " format "\n", \
1519 ##__VA_ARGS__)
1620
21+ const char * objname ;
22+
1723struct opts opts ;
1824
1925static const char * const check_usage [] = {
@@ -71,7 +77,7 @@ const struct option check_options[] = {
7177 OPT_BOOLEAN ('i' , "ibt" , & opts .ibt , "validate and annotate IBT" ),
7278 OPT_BOOLEAN ('m' , "mcount" , & opts .mcount , "annotate mcount/fentry calls for ftrace" ),
7379 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" ),
7581 OPT_BOOLEAN ('r' , "retpoline" , & opts .retpoline , "validate and annotate retpoline usage" ),
7682 OPT_BOOLEAN (0 , "rethunk" , & opts .rethunk , "validate and annotate rethunk usage" ),
7783 OPT_BOOLEAN (0 , "unret" , & opts .unret , "validate entry unret placement" ),
@@ -83,15 +89,16 @@ const struct option check_options[] = {
8389 OPT_CALLBACK_OPTARG (0 , "dump" , NULL , NULL , "orc" , "dump metadata" , parse_dump ),
8490
8591 OPT_GROUP ("Options:" ),
86- OPT_BOOLEAN (0 , "backtrace" , & opts .backtrace , "unwind on error" ),
87- OPT_BOOLEAN (0 , "backup" , & opts .backup , "create .orig files before modification" ),
88- OPT_BOOLEAN (0 , "dry-run" , & opts .dryrun , "don't write modifications" ),
89- OPT_BOOLEAN (0 , "link" , & opts .link , "object is a linked object" ),
90- OPT_BOOLEAN (0 , "module" , & opts .module , "object is part of a kernel module" ),
91- OPT_BOOLEAN (0 , "mnop" , & opts .mnop , "nop out mcount call sites" ),
92- OPT_BOOLEAN (0 , "no-unreachable" , & opts .no_unreachable , "skip 'unreachable instruction' warnings" ),
93- OPT_BOOLEAN (0 , "sec-address" , & opts .sec_address , "print section addresses in warnings" ),
94- OPT_BOOLEAN (0 , "stats" , & opts .stats , "print statistics" ),
92+ OPT_BOOLEAN (0 , "backtrace" , & opts .backtrace , "unwind on error" ),
93+ OPT_BOOLEAN (0 , "dry-run" , & opts .dryrun , "don't write modifications" ),
94+ OPT_BOOLEAN (0 , "link" , & opts .link , "object is a linked object" ),
95+ OPT_BOOLEAN (0 , "module" , & opts .module , "object is part of a kernel module" ),
96+ OPT_BOOLEAN (0 , "mnop" , & opts .mnop , "nop out mcount call sites" ),
97+ OPT_BOOLEAN (0 , "no-unreachable" , & opts .no_unreachable , "skip 'unreachable instruction' warnings" ),
98+ OPT_STRING ('o' , "output" , & opts .output , "file" , "output file name" ),
99+ OPT_BOOLEAN (0 , "sec-address" , & opts .sec_address , "print section addresses in warnings" ),
100+ OPT_BOOLEAN (0 , "stats" , & opts .stats , "print statistics" ),
101+ OPT_BOOLEAN (0 , "Werror" , & opts .werror , "return error on warnings" ),
95102
96103 OPT_END (),
97104};
@@ -190,37 +197,157 @@ static bool link_opts_valid(struct objtool_file *file)
190197 return true;
191198}
192199
200+ static int copy_file (const char * src , const char * dst )
201+ {
202+ size_t to_copy , copied ;
203+ int dst_fd , src_fd ;
204+ struct stat stat ;
205+ off_t offset = 0 ;
206+
207+ src_fd = open (src , O_RDONLY );
208+ if (src_fd == -1 ) {
209+ ERROR ("can't open '%s' for reading" , src );
210+ return 1 ;
211+ }
212+
213+ dst_fd = open (dst , O_WRONLY | O_CREAT | O_TRUNC , 0400 );
214+ if (dst_fd == -1 ) {
215+ ERROR ("can't open '%s' for writing" , dst );
216+ return 1 ;
217+ }
218+
219+ if (fstat (src_fd , & stat ) == -1 ) {
220+ perror ("fstat" );
221+ return 1 ;
222+ }
223+
224+ if (fchmod (dst_fd , stat .st_mode ) == -1 ) {
225+ perror ("fchmod" );
226+ return 1 ;
227+ }
228+
229+ for (to_copy = stat .st_size ; to_copy > 0 ; to_copy -= copied ) {
230+ copied = sendfile (dst_fd , src_fd , & offset , to_copy );
231+ if (copied == -1 ) {
232+ perror ("sendfile" );
233+ return 1 ;
234+ }
235+ }
236+
237+ close (dst_fd );
238+ close (src_fd );
239+ return 0 ;
240+ }
241+
242+ static char * * save_argv (int argc , const char * * argv )
243+ {
244+ char * * orig_argv ;
245+
246+ orig_argv = calloc (argc , sizeof (char * ));
247+ if (!orig_argv ) {
248+ perror ("calloc" );
249+ return NULL ;
250+ }
251+
252+ for (int i = 0 ; i < argc ; i ++ ) {
253+ orig_argv [i ] = strdup (argv [i ]);
254+ if (!orig_argv [i ]) {
255+ perror ("strdup" );
256+ return NULL ;
257+ }
258+ };
259+
260+ return orig_argv ;
261+ }
262+
263+ #define ORIG_SUFFIX ".orig"
264+
193265int objtool_run (int argc , const char * * argv )
194266{
195- const char * objname ;
196267 struct objtool_file * file ;
197- int ret ;
268+ char * backup = NULL ;
269+ char * * orig_argv ;
270+ int ret = 0 ;
198271
199- argc = cmd_parse_options (argc , argv , check_usage );
200- objname = argv [0 ];
272+ orig_argv = save_argv (argc , argv );
273+ if (!orig_argv )
274+ return 1 ;
275+
276+ cmd_parse_options (argc , argv , check_usage );
201277
202278 if (!opts_valid ())
203279 return 1 ;
204280
281+ objname = argv [0 ];
282+
205283 if (opts .dump_orc )
206284 return orc_dump (objname );
207285
286+ if (!opts .dryrun && opts .output ) {
287+ /* copy original .o file to output file */
288+ if (copy_file (objname , opts .output ))
289+ return 1 ;
290+
291+ /* from here on, work directly on the output file */
292+ objname = opts .output ;
293+ }
294+
208295 file = objtool_open_read (objname );
209296 if (!file )
210- return 1 ;
297+ goto err ;
211298
212299 if (!mnop_opts_valid ())
213- return 1 ;
300+ goto err ;
214301
215302 if (!link_opts_valid (file ))
216- return 1 ;
303+ goto err ;
217304
218305 ret = check (file );
219306 if (ret )
220- return ret ;
307+ goto err ;
221308
222- if (file -> elf -> changed )
223- return elf_write ( file -> elf ) ;
309+ if (! opts . dryrun && file -> elf -> changed && elf_write ( file -> elf ) )
310+ goto err ;
224311
225312 return 0 ;
313+
314+ err :
315+ if (opts .dryrun )
316+ goto err_msg ;
317+
318+ if (opts .output ) {
319+ unlink (opts .output );
320+ goto err_msg ;
321+ }
322+
323+ /*
324+ * Make a backup before kbuild deletes the file so the error
325+ * can be recreated without recompiling or relinking.
326+ */
327+ backup = malloc (strlen (objname ) + strlen (ORIG_SUFFIX ) + 1 );
328+ if (!backup ) {
329+ perror ("malloc" );
330+ return 1 ;
331+ }
332+
333+ strcpy (backup , objname );
334+ strcat (backup , ORIG_SUFFIX );
335+ if (copy_file (objname , backup ))
336+ return 1 ;
337+
338+ err_msg :
339+ fprintf (stderr , "%s" , orig_argv [0 ]);
340+
341+ for (int i = 1 ; i < argc ; i ++ ) {
342+ char * arg = orig_argv [i ];
343+
344+ if (backup && !strcmp (arg , objname ))
345+ fprintf (stderr , " %s -o %s" , backup , objname );
346+ else
347+ fprintf (stderr , " %s" , arg );
348+ }
349+
350+ fprintf (stderr , "\n" );
351+
352+ return 1 ;
226353}
0 commit comments