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 @@ static 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" ),
@@ -84,15 +90,16 @@ static const struct option check_options[] = {
8490 OPT_CALLBACK_OPTARG (0 , "dump" , NULL , NULL , "orc" , "dump metadata" , parse_dump ),
8591
8692 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" ),
96103 OPT_BOOLEAN ('v' , "verbose" , & opts .verbose , "verbose warnings" ),
97104
98105 OPT_END (),
@@ -178,24 +185,75 @@ static bool opts_valid(void)
178185 return false;
179186}
180187
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+
181230int objtool_run (int argc , const char * * argv )
182231{
183- const char * objname ;
184232 struct objtool_file * file ;
185233 int ret ;
186234
187- argc = cmd_parse_options (argc , argv , check_usage );
188- objname = argv [0 ];
235+ cmd_parse_options (argc , argv , check_usage );
189236
190237 if (!opts_valid ())
191238 return 1 ;
192239
240+ objname = argv [0 ];
241+
193242 if (opts .dump_orc )
194243 return orc_dump (objname );
195244
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+
196254 file = objtool_open_read (objname );
197255 if (!file )
198- return 1 ;
256+ goto err ;
199257
200258 if (!opts .link && has_multiple_files (file -> elf )) {
201259 ERROR ("Linked object requires --link" );
@@ -204,10 +262,16 @@ int objtool_run(int argc, const char **argv)
204262
205263 ret = check (file );
206264 if (ret )
207- return ret ;
265+ goto err ;
208266
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 ;
211269
212270 return 0 ;
271+
272+ err :
273+ if (opts .output )
274+ unlink (opts .output );
275+
276+ return 1 ;
213277}
0 commit comments