2009-12-02 Rafael Avila de Espindola <espindola@google.com>
[external/binutils.git] / gold / incremental.cc
1 // inremental.cc -- incremental linking support for gold
2
3 // Copyright 2009 Free Software Foundation, Inc.
4 // Written by Mikolaj Zalewski <mikolajz@google.com>.
5
6 // This file is part of gold.
7
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
12
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 // MA 02110-1301, USA.
22
23 #include "gold.h"
24
25 #include <cstdarg>
26
27 #include "elfcpp.h"
28 #include "output.h"
29 #include "incremental.h"
30 #include "archive.h"
31 #include "output.h"
32 #include "target-select.h"
33
34 using elfcpp::Convert;
35
36 namespace gold {
37
38 // Version information. Will change frequently during the development, later
39 // we could think about backward (and forward?) compatibility.
40 const unsigned int INCREMENTAL_LINK_VERSION = 1;
41
42 // Accessors.
43
44 // Reader class for .gnu_incremental_inputs header. See
45 // Incremental_inputs_header_data for fields descriptions.
46
47 template<int size, bool big_endian>
48 class Incremental_inputs_header
49 {
50  private:
51   typedef Incremental_inputs_header_data Data_type;
52
53  public:
54   Incremental_inputs_header(const unsigned char *p)
55     : p_(reinterpret_cast<const Data_type*>(p))
56   { }
57
58   static const int data_size = sizeof(Data_type);
59
60   elfcpp::Elf_Word
61   get_version() const
62   { return Convert<32, big_endian>::convert_host(this->p_->version); }
63
64   elfcpp::Elf_Word
65   get_input_file_count() const
66   { return Convert<32, big_endian>::convert_host(this->p_->input_file_count); }
67
68   elfcpp::Elf_Word
69   get_command_line_offset() const
70   { return Convert<32, big_endian>::convert_host(this->p_->command_line_offset); }
71
72   elfcpp::Elf_Word
73   get_reserved() const
74   { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
75
76  private:
77   const Data_type* p_;
78 };
79
80 // Writer class for .gnu_incremental_inputs header. See
81 // Incremental_inputs_header_data for fields descriptions.
82
83 template<int size, bool big_endian>
84 class Incremental_inputs_header_write
85 {
86  private:
87   typedef Incremental_inputs_header_data Data_type;
88
89  public:
90   Incremental_inputs_header_write(unsigned char *p)
91     : p_(reinterpret_cast<Data_type*>(p))
92   { }
93
94   static const int data_size = sizeof(Data_type);
95
96   void
97   put_version(elfcpp::Elf_Word v)
98   { this->p_->version = Convert<32, big_endian>::convert_host(v); }
99
100   void
101   put_input_file_count(elfcpp::Elf_Word v)
102   { this->p_->input_file_count = Convert<32, big_endian>::convert_host(v); }
103
104   void
105   put_command_line_offset(elfcpp::Elf_Word v)
106   { this->p_->command_line_offset = Convert<32, big_endian>::convert_host(v); }
107
108   void
109   put_reserved(elfcpp::Elf_Word v)
110   { this->p_->reserved = Convert<32, big_endian>::convert_host(v); }
111
112  private:
113   Data_type* p_;
114 };
115
116 // Reader class for an .gnu_incremental_inputs entry. See
117 // Incremental_inputs_entry_data for fields descriptions.
118 template<int size, bool big_endian>
119 class Incremental_inputs_entry
120 {
121  private:
122   typedef Incremental_inputs_entry_data Data_type;
123
124  public:
125   Incremental_inputs_entry(const unsigned char *p)
126     : p_(reinterpret_cast<const Data_type*>(p))
127   { }
128
129   static const int data_size = sizeof(Data_type);
130
131   elfcpp::Elf_Word
132   get_filename_offset()
133   { return Convert<32, big_endian>::convert_host(this->p_->filename_offset); }
134
135   elfcpp::Elf_Word
136   get_data_offset()
137   { return Convert<32, big_endian>::convert_host(this->p_->data_offset); }
138
139   elfcpp::Elf_Xword
140   get_timestamp_sec()
141   { return Convert<64, big_endian>::convert_host(this->p_->timestamp_sec); }
142
143   elfcpp::Elf_Word
144   get_timestamp_nsec()
145   { return Convert<32, big_endian>::convert_host(this->p_->timestamp_nsec); }
146
147   elfcpp::Elf_Word
148   get_input_type()
149   { return Convert<32, big_endian>::convert_host(this->p_->input_type); }
150
151   elfcpp::Elf_Word
152   get_reserved()
153   { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
154
155  private:
156   const Data_type* p_;
157 };
158
159 // Writer class for an .gnu_incremental_inputs entry. See
160 // Incremental_inputs_entry_data for fields descriptions.
161 template<int size, bool big_endian>
162 class Incremental_inputs_entry_write
163 {
164  private:
165   typedef Incremental_inputs_entry_data Data_type;
166
167  public:
168   Incremental_inputs_entry_write(unsigned char *p)
169     : p_(reinterpret_cast<Data_type*>(p))
170   { }
171
172   static const int data_size = sizeof(Data_type);
173
174   void
175   put_filename_offset(elfcpp::Elf_Word v)
176   { this->p_->filename_offset = Convert<32, big_endian>::convert_host(v); }
177
178   void
179   put_data_offset(elfcpp::Elf_Word v)
180   { this->p_->data_offset = Convert<32, big_endian>::convert_host(v); }
181
182   void
183   put_timestamp_sec(elfcpp::Elf_Xword v)
184   { this->p_->timestamp_sec = Convert<64, big_endian>::convert_host(v); }
185
186   void
187   put_timestamp_nsec(elfcpp::Elf_Word v)
188   { this->p_->timestamp_nsec = Convert<32, big_endian>::convert_host(v); }
189
190   void
191   put_input_type(elfcpp::Elf_Word v)
192   { this->p_->input_type = Convert<32, big_endian>::convert_host(v); }
193
194   void
195   put_reserved(elfcpp::Elf_Word v)
196   { this->p_->reserved = Convert<32, big_endian>::convert_host(v); }
197
198  private:
199   Data_type* p_;
200 };
201
202 // Inform the user why we don't do an incremental link.  Not called in
203 // the obvious case of missing output file.  TODO: Is this helpful?
204
205 void
206 vexplain_no_incremental(const char* format, va_list args)
207 {
208   char* buf = NULL;
209   if (vasprintf(&buf, format, args) < 0)
210     gold_nomem();
211   gold_info(_("the link might take longer: "
212               "cannot perform incremental link: %s"), buf);
213   free(buf);
214 }
215
216 void
217 explain_no_incremental(const char* format, ...)
218 {
219   va_list args;
220   va_start(args, format);
221   vexplain_no_incremental(format, args);
222   va_end(args);
223 }
224
225 // Report an error.
226
227 void
228 Incremental_binary::error(const char* format, ...) const
229 {
230   va_list args;
231   va_start(args, format);
232   // Current code only checks if the file can be used for incremental linking,
233   // so errors shouldn't fail the build, but only result in a fallback to a
234   // full build.
235   // TODO: when we implement incremental editing of the file, we may need a
236   // flag that will cause errors to be treated seriously.
237   vexplain_no_incremental(format, args);
238   va_end(args);
239 }
240
241 template<int size, bool big_endian>
242 bool
243 Sized_incremental_binary<size, big_endian>::do_find_incremental_inputs_section(
244     Location* location,
245     unsigned int* strtab_shndx)
246 {
247   unsigned int shndx = this->elf_file_.find_section_by_type(
248       elfcpp::SHT_GNU_INCREMENTAL_INPUTS);
249   if (shndx == elfcpp::SHN_UNDEF)  // Not found.
250     return false;
251   *strtab_shndx = this->elf_file_.section_link(shndx);
252   *location = this->elf_file_.section_contents(shndx);
253   return true;
254 }
255
256 template<int size, bool big_endian>
257 bool
258 Sized_incremental_binary<size, big_endian>::do_check_inputs(
259     Incremental_inputs* incremental_inputs)
260 {
261   const int entry_size =
262       Incremental_inputs_entry_write<size, big_endian>::data_size;
263   const int header_size =
264       Incremental_inputs_header_write<size, big_endian>::data_size;
265
266   unsigned int strtab_shndx;
267   Location location;
268
269   if (!do_find_incremental_inputs_section(&location, &strtab_shndx))
270     {
271       explain_no_incremental(_("no incremental data from previous build"));
272       return false;
273     }
274   if (location.data_size < header_size
275       || strtab_shndx >= this->elf_file_.shnum()
276       || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
277     {
278       explain_no_incremental(_("invalid incremental build data"));
279       return false;
280     }
281
282   Location strtab_location(this->elf_file_.section_contents(strtab_shndx));
283   View data_view(view(location));
284   View strtab_view(view(strtab_location));
285   elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
286   Incremental_inputs_header<size, big_endian> header(data_view.data());
287
288   if (header.get_version() != INCREMENTAL_LINK_VERSION)
289     {
290       explain_no_incremental(_("different version of incremental build data"));
291       return false;
292     }
293
294   const char* command_line;
295   // We divide instead of multiplying to make sure there is no integer
296   // overflow.
297   size_t max_input_entries = (location.data_size - header_size) / entry_size;
298   if (header.get_input_file_count() > max_input_entries
299       || !strtab.get_c_string(header.get_command_line_offset(), &command_line))
300     {
301       explain_no_incremental(_("invalid incremental build data"));
302       return false;
303     }
304
305   if (incremental_inputs->command_line() != command_line)
306     {
307       explain_no_incremental(_("command line changed"));
308       return false;
309     }
310
311   // TODO: compare incremental_inputs->inputs() with entries in data_view.
312   return true;
313 }
314
315 namespace
316 {
317
318 // Create a Sized_incremental_binary object of the specified size and
319 // endianness. Fails if the target architecture is not supported.
320
321 template<int size, bool big_endian>
322 Incremental_binary*
323 make_sized_incremental_binary(Output_file* file,
324                               const elfcpp::Ehdr<size, big_endian>& ehdr)
325 {
326   Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
327                                  ehdr.get_e_ident()[elfcpp::EI_OSABI],
328                                  ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
329   if (target == NULL)
330     {
331       explain_no_incremental(_("unsupported ELF machine number %d"),
332                ehdr.get_e_machine());
333       return NULL;
334     }
335
336   if (!parameters->target_valid())
337     set_parameters_target(target);
338   else if (target != &parameters->target())
339     gold_error(_("%s: incompatible target"), file->filename());
340
341   return new Sized_incremental_binary<size, big_endian>(file, ehdr, target);
342 }
343
344 }  // End of anonymous namespace.
345
346 // Create an Incremental_binary object for FILE. Returns NULL is this is not
347 // possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
348 // should be opened.
349
350 Incremental_binary*
351 open_incremental_binary(Output_file* file)
352 {
353   off_t filesize = file->filesize();
354   int want = elfcpp::Elf_recognizer::max_header_size;
355   if (filesize < want)
356     want = filesize;
357
358   const unsigned char* p = file->get_input_view(0, want);
359   if (!elfcpp::Elf_recognizer::is_elf_file(p, want))
360     {
361       explain_no_incremental(_("output is not an ELF file."));
362       return NULL;
363     }
364
365   int size = 0;
366   bool big_endian = false;
367   std::string error;
368   if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
369                                                &error))
370     {
371       explain_no_incremental(error.c_str());
372       return NULL;
373     }
374
375   Incremental_binary* result = NULL;
376   if (size == 32)
377     {
378       if (big_endian)
379         {
380 #ifdef HAVE_TARGET_32_BIG
381           result = make_sized_incremental_binary<32, true>(
382               file, elfcpp::Ehdr<32, true>(p));
383 #else
384           explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
385 #endif
386         }
387       else
388         {
389 #ifdef HAVE_TARGET_32_LITTLE
390           result = make_sized_incremental_binary<32, false>(
391               file, elfcpp::Ehdr<32, false>(p));
392 #else
393           explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
394 #endif
395         }
396     }
397   else if (size == 64)
398     {
399       if (big_endian)
400         {
401 #ifdef HAVE_TARGET_64_BIG
402           result = make_sized_incremental_binary<64, true>(
403               file, elfcpp::Ehdr<64, true>(p));
404 #else
405           explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
406 #endif
407         }
408       else
409         {
410 #ifdef HAVE_TARGET_64_LITTLE
411           result = make_sized_incremental_binary<64, false>(
412               file, elfcpp::Ehdr<64, false>(p));
413 #else
414           explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
415 #endif
416         }
417     }
418   else
419     gold_unreachable();
420
421   return result;
422 }
423
424 // Analyzes the output file to check if incremental linking is possible and
425 // (to be done) what files need to be relinked.
426
427 bool
428 Incremental_checker::can_incrementally_link_output_file()
429 {
430   Output_file output(this->output_name_);
431   if (!output.open_for_modification())
432     return false;
433   Incremental_binary* binary = open_incremental_binary(&output);
434   if (binary == NULL)
435     return false;
436   return binary->check_inputs(this->incremental_inputs_);
437 }
438
439 // Add the command line to the string table, setting
440 // command_line_key_.  In incremental builds, the command line is
441 // stored in .gnu_incremental_inputs so that the next linker run can
442 // check if the command line options didn't change.
443
444 void
445 Incremental_inputs::report_command_line(int argc, const char* const* argv)
446 {
447   // Always store 'gold' as argv[0] to avoid a full relink if the user used a
448   // different path to the linker.
449   std::string args("gold");
450   // Copied from collect_argv in main.cc.
451   for (int i = 1; i < argc; ++i)
452     {
453       // Adding/removing these options should result in a full relink.
454       if (strcmp(argv[i], "--incremental-changed") == 0
455           || strcmp(argv[i], "--incremental-unchanged") == 0
456           || strcmp(argv[i], "--incremental-unknown") == 0)
457         continue;
458
459       args.append(" '");
460       // Now append argv[i], but with all single-quotes escaped
461       const char* argpos = argv[i];
462       while (1)
463         {
464           const int len = strcspn(argpos, "'");
465           args.append(argpos, len);
466           if (argpos[len] == '\0')
467             break;
468           args.append("'\"'\"'");
469           argpos += len + 1;
470         }
471       args.append("'");
472     }
473
474   this->command_line_ = args;
475   this->strtab_->add(this->command_line_.c_str(), false,
476                      &this->command_line_key_);
477 }
478
479 // Record that the input argument INPUT is an achive ARCHIVE.  This is
480 // called by Read_symbols after finding out the type of the file.
481
482 void
483 Incremental_inputs::report_archive(const Input_argument* input,
484                                    Archive* archive)
485 {
486   Hold_lock hl(*this->lock_);
487
488   Input_info info;
489   info.type = INCREMENTAL_INPUT_ARCHIVE;
490   info.archive = archive;
491   info.mtime = archive->file().get_mtime();
492   this->inputs_map_.insert(std::make_pair(input, info));
493 }
494
495 // Record that the input argument INPUT is an object OBJ.  This is
496 // called by Read_symbols after finding out the type of the file.
497
498 void
499 Incremental_inputs::report_object(const Input_argument* input,
500                                   Object* obj)
501 {
502   Hold_lock hl(*this->lock_);
503
504   Input_info info;
505   info.type = (obj->is_dynamic()
506                ? INCREMENTAL_INPUT_SHARED_LIBRARY
507                : INCREMENTAL_INPUT_OBJECT);
508   info.object = obj;
509   info.mtime = obj->input_file()->file().get_mtime();
510   this->inputs_map_.insert(std::make_pair(input, info));
511 }
512
513 // Record that the input argument INPUT is an script SCRIPT.  This is
514 // called by read_script after parsing the script and reading the list
515 // of inputs added by this script.
516
517 void
518 Incremental_inputs::report_script(const Input_argument* input,
519                                   Timespec mtime,
520                                   Script_info* script)
521 {
522   Hold_lock hl(*this->lock_);
523
524   Input_info info;
525   info.type = INCREMENTAL_INPUT_SCRIPT;
526   info.script = script;
527   info.mtime = mtime;
528   this->inputs_map_.insert(std::make_pair(input, info));
529 }
530
531 // Compute indexes in the order in which the inputs should appear in
532 // .gnu_incremental_inputs.  This needs to be done after all the
533 // scripts are parsed.  The function is first called for the command
534 // line inputs arguments and may call itself recursively for e.g. a
535 // list of elements of a group or a list of inputs added by a script.
536 // The [BEGIN; END) interval to analyze and *INDEX is the current
537 // value of the index (that will be updated).
538
539 void
540 Incremental_inputs::finalize_inputs(
541     Input_argument_list::const_iterator begin,
542     Input_argument_list::const_iterator end,
543     unsigned int* index)
544 {
545   for (Input_argument_list::const_iterator p = begin; p != end; ++p)
546     {
547       if (p->is_group())
548         {
549           finalize_inputs(p->group()->begin(), p->group()->end(), index);
550           continue;
551         }
552
553       Inputs_info_map::iterator it = this->inputs_map_.find(&(*p));
554       // TODO: turn it into an assert when the code will be more stable.
555       if (it == this->inputs_map_.end())
556         {
557           gold_error("internal error: %s: incremental build info not provided",
558                      (p->is_file() ? p->file().name() : "[group]"));
559           continue;
560         }
561       Input_info* info = &it->second;
562       info->index = *index;
563       (*index)++;
564       this->strtab_->add(p->file().name(), false, &info->filename_key);
565       if (info->type == INCREMENTAL_INPUT_SCRIPT)
566         {
567           finalize_inputs(info->script->inputs()->begin(),
568                           info->script->inputs()->end(),
569                           index);
570         }
571     }
572 }
573
574 // Finalize the incremental link information.  Called from
575 // Layout::finalize.
576
577 void
578 Incremental_inputs::finalize()
579 {
580   unsigned int index = 0;
581   finalize_inputs(this->inputs_->begin(), this->inputs_->end(), &index);
582
583   // Sanity check.
584   for (Inputs_info_map::const_iterator p = this->inputs_map_.begin();
585        p != this->inputs_map_.end();
586        ++p)
587     {
588       gold_assert(p->second.filename_key != 0);
589     }
590
591   this->strtab_->set_string_offsets();
592 }
593
594 // Create the content of the .gnu_incremental_inputs section.
595
596 Output_section_data*
597 Incremental_inputs::create_incremental_inputs_section_data()
598 {
599   switch (parameters->size_and_endianness())
600     {
601 #ifdef HAVE_TARGET_32_LITTLE
602     case Parameters::TARGET_32_LITTLE:
603       return this->sized_create_inputs_section_data<32, false>();
604 #endif
605 #ifdef HAVE_TARGET_32_BIG
606     case Parameters::TARGET_32_BIG:
607       return this->sized_create_inputs_section_data<32, true>();
608 #endif
609 #ifdef HAVE_TARGET_64_LITTLE
610     case Parameters::TARGET_64_LITTLE:
611       return this->sized_create_inputs_section_data<64, false>();
612 #endif
613 #ifdef HAVE_TARGET_64_BIG
614     case Parameters::TARGET_64_BIG:
615       return this->sized_create_inputs_section_data<64, true>();
616 #endif
617     default:
618       gold_unreachable();
619     }
620 }
621
622 // Sized creation of .gnu_incremental_inputs section.
623
624 template<int size, bool big_endian>
625 Output_section_data*
626 Incremental_inputs::sized_create_inputs_section_data()
627 {
628   const int entry_size =
629       Incremental_inputs_entry_write<size, big_endian>::data_size;
630   const int header_size =
631       Incremental_inputs_header_write<size, big_endian>::data_size;
632
633   unsigned int sz = header_size + entry_size * this->inputs_map_.size();
634   unsigned char* buffer = new unsigned char[sz];
635   unsigned char* inputs_base = buffer + header_size;
636
637   Incremental_inputs_header_write<size, big_endian> header_writer(buffer);
638   gold_assert(this->command_line_key_ > 0);
639   int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_);
640
641   header_writer.put_version(INCREMENTAL_LINK_VERSION);
642   header_writer.put_input_file_count(this->inputs_map_.size());
643   header_writer.put_command_line_offset(cmd_offset);
644   header_writer.put_reserved(0);
645
646   for (Inputs_info_map::const_iterator it = this->inputs_map_.begin();
647        it != this->inputs_map_.end();
648        ++it)
649     {
650       gold_assert(it->second.index < this->inputs_map_.size());
651
652       unsigned char* entry_buffer =
653           inputs_base + it->second.index * entry_size;
654       Incremental_inputs_entry_write<size, big_endian> entry(entry_buffer);
655       int filename_offset =
656           this->strtab_->get_offset_from_key(it->second.filename_key);
657       entry.put_filename_offset(filename_offset);
658       switch (it->second.type)
659         {
660         case INCREMENTAL_INPUT_SCRIPT:
661           entry.put_data_offset(0);
662           break;
663         case INCREMENTAL_INPUT_ARCHIVE:
664         case INCREMENTAL_INPUT_OBJECT:
665         case INCREMENTAL_INPUT_SHARED_LIBRARY:
666           // TODO: add per input data.  Currently we store
667           // an out-of-bounds offset for future version of gold to reject
668           // such an incremental_inputs section.
669           entry.put_data_offset(0xffffffff);
670           break;
671         default:
672           gold_unreachable();
673         }
674       // TODO: add per input data and timestamp.  Currently we store
675       // an out-of-bounds offset for future version of gold to reject
676       // such an incremental_inputs section.
677       entry.put_data_offset(0xffffffff);
678       entry.put_timestamp_sec(it->second.mtime.seconds);
679       entry.put_timestamp_nsec(it->second.mtime.nanoseconds);
680       entry.put_input_type(it->second.type);
681       entry.put_reserved(0);
682     }
683
684   return new Output_data_const_buffer(buffer, sz, 8,
685                                       "** incremental link inputs list");
686 }
687
688 // Instantiate the templates we need.
689
690 #ifdef HAVE_TARGET_32_LITTLE
691 template
692 class Sized_incremental_binary<32, false>;
693 #endif
694
695 #ifdef HAVE_TARGET_32_BIG
696 template
697 class Sized_incremental_binary<32, true>;
698 #endif
699
700 #ifdef HAVE_TARGET_64_LITTLE
701 template
702 class Sized_incremental_binary<64, false>;
703 #endif
704
705 #ifdef HAVE_TARGET_64_BIG
706 template
707 class Sized_incremental_binary<64, true>;
708 #endif
709
710 } // End namespace gold.