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   return new Sized_incremental_binary<size, big_endian>(file, ehdr, target);
337 }
338
339 }  // End of anonymous namespace.
340
341 // Create an Incremental_binary object for FILE. Returns NULL is this is not
342 // possible, e.g. FILE is not an ELF file or has an unsupported target. FILE
343 // should be opened.
344
345 Incremental_binary*
346 open_incremental_binary(Output_file* file)
347 {
348   off_t filesize = file->filesize();
349   int want = elfcpp::Elf_recognizer::max_header_size;
350   if (filesize < want)
351     want = filesize;
352
353   const unsigned char* p = file->get_input_view(0, want);
354   if (!elfcpp::Elf_recognizer::is_elf_file(p, want))
355     {
356       explain_no_incremental(_("output is not an ELF file."));
357       return NULL;
358     }
359
360   int size = 0;
361   bool big_endian = false;
362   std::string error;
363   if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
364                                                &error))
365     {
366       explain_no_incremental(error.c_str());
367       return NULL;
368     }
369
370   Incremental_binary* result = NULL;
371   if (size == 32)
372     {
373       if (big_endian)
374         {
375 #ifdef HAVE_TARGET_32_BIG
376           result = make_sized_incremental_binary<32, true>(
377               file, elfcpp::Ehdr<32, true>(p));
378 #else
379           explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
380 #endif
381         }
382       else
383         {
384 #ifdef HAVE_TARGET_32_LITTLE
385           result = make_sized_incremental_binary<32, false>(
386               file, elfcpp::Ehdr<32, false>(p));
387 #else
388           explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
389 #endif
390         }
391     }
392   else if (size == 64)
393     {
394       if (big_endian)
395         {
396 #ifdef HAVE_TARGET_64_BIG
397           result = make_sized_incremental_binary<64, true>(
398               file, elfcpp::Ehdr<64, true>(p));
399 #else
400           explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
401 #endif
402         }
403       else
404         {
405 #ifdef HAVE_TARGET_64_LITTLE
406           result = make_sized_incremental_binary<64, false>(
407               file, elfcpp::Ehdr<64, false>(p));
408 #else
409           explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
410 #endif
411         }
412     }
413   else
414     gold_unreachable();
415
416   return result;
417 }
418
419 // Analyzes the output file to check if incremental linking is possible and
420 // (to be done) what files need to be relinked.
421
422 bool
423 Incremental_checker::can_incrementally_link_output_file()
424 {
425   Output_file output(this->output_name_);
426   if (!output.open_for_modification())
427     return false;
428   Incremental_binary* binary = open_incremental_binary(&output);
429   if (binary == NULL)
430     return false;
431   return binary->check_inputs(this->incremental_inputs_);
432 }
433
434 // Add the command line to the string table, setting
435 // command_line_key_.  In incremental builds, the command line is
436 // stored in .gnu_incremental_inputs so that the next linker run can
437 // check if the command line options didn't change.
438
439 void
440 Incremental_inputs::report_command_line(int argc, const char* const* argv)
441 {
442   // Always store 'gold' as argv[0] to avoid a full relink if the user used a
443   // different path to the linker.
444   std::string args("gold");
445   // Copied from collect_argv in main.cc.
446   for (int i = 1; i < argc; ++i)
447     {
448       // Adding/removing these options should result in a full relink.
449       if (strcmp(argv[i], "--incremental-changed") == 0
450           || strcmp(argv[i], "--incremental-unchanged") == 0
451           || strcmp(argv[i], "--incremental-unknown") == 0)
452         continue;
453
454       args.append(" '");
455       // Now append argv[i], but with all single-quotes escaped
456       const char* argpos = argv[i];
457       while (1)
458         {
459           const int len = strcspn(argpos, "'");
460           args.append(argpos, len);
461           if (argpos[len] == '\0')
462             break;
463           args.append("'\"'\"'");
464           argpos += len + 1;
465         }
466       args.append("'");
467     }
468
469   this->command_line_ = args;
470   this->strtab_->add(this->command_line_.c_str(), false,
471                      &this->command_line_key_);
472 }
473
474 // Record that the input argument INPUT is an achive ARCHIVE.  This is
475 // called by Read_symbols after finding out the type of the file.
476
477 void
478 Incremental_inputs::report_archive(const Input_argument* input,
479                                    Archive* archive)
480 {
481   Hold_lock hl(*this->lock_);
482
483   Input_info info;
484   info.type = INCREMENTAL_INPUT_ARCHIVE;
485   info.archive = archive;
486   info.mtime = archive->file().get_mtime();
487   this->inputs_map_.insert(std::make_pair(input, info));
488 }
489
490 // Record that the input argument INPUT is an object OBJ.  This is
491 // called by Read_symbols after finding out the type of the file.
492
493 void
494 Incremental_inputs::report_object(const Input_argument* input,
495                                   Object* obj)
496 {
497   Hold_lock hl(*this->lock_);
498
499   Input_info info;
500   info.type = (obj->is_dynamic()
501                ? INCREMENTAL_INPUT_SHARED_LIBRARY
502                : INCREMENTAL_INPUT_OBJECT);
503   info.object = obj;
504   info.mtime = obj->input_file()->file().get_mtime();
505   this->inputs_map_.insert(std::make_pair(input, info));
506 }
507
508 // Record that the input argument INPUT is an script SCRIPT.  This is
509 // called by read_script after parsing the script and reading the list
510 // of inputs added by this script.
511
512 void
513 Incremental_inputs::report_script(const Input_argument* input,
514                                   Timespec mtime,
515                                   Script_info* script)
516 {
517   Hold_lock hl(*this->lock_);
518
519   Input_info info;
520   info.type = INCREMENTAL_INPUT_SCRIPT;
521   info.script = script;
522   info.mtime = mtime;
523   this->inputs_map_.insert(std::make_pair(input, info));
524 }
525
526 // Compute indexes in the order in which the inputs should appear in
527 // .gnu_incremental_inputs.  This needs to be done after all the
528 // scripts are parsed.  The function is first called for the command
529 // line inputs arguments and may call itself recursively for e.g. a
530 // list of elements of a group or a list of inputs added by a script.
531 // The [BEGIN; END) interval to analyze and *INDEX is the current
532 // value of the index (that will be updated).
533
534 void
535 Incremental_inputs::finalize_inputs(
536     Input_argument_list::const_iterator begin,
537     Input_argument_list::const_iterator end,
538     unsigned int* index)
539 {
540   for (Input_argument_list::const_iterator p = begin; p != end; ++p)
541     {
542       if (p->is_group())
543         {
544           finalize_inputs(p->group()->begin(), p->group()->end(), index);
545           continue;
546         }
547
548       Inputs_info_map::iterator it = this->inputs_map_.find(&(*p));
549       // TODO: turn it into an assert when the code will be more stable.
550       if (it == this->inputs_map_.end())
551         {
552           gold_error("internal error: %s: incremental build info not provided",
553                      (p->is_file() ? p->file().name() : "[group]"));
554           continue;
555         }
556       Input_info* info = &it->second;
557       info->index = *index;
558       (*index)++;
559       this->strtab_->add(p->file().name(), false, &info->filename_key);
560       if (info->type == INCREMENTAL_INPUT_SCRIPT)
561         {
562           finalize_inputs(info->script->inputs()->begin(),
563                           info->script->inputs()->end(),
564                           index);
565         }
566     }
567 }
568
569 // Finalize the incremental link information.  Called from
570 // Layout::finalize.
571
572 void
573 Incremental_inputs::finalize()
574 {
575   unsigned int index = 0;
576   finalize_inputs(this->inputs_->begin(), this->inputs_->end(), &index);
577
578   // Sanity check.
579   for (Inputs_info_map::const_iterator p = this->inputs_map_.begin();
580        p != this->inputs_map_.end();
581        ++p)
582     {
583       gold_assert(p->second.filename_key != 0);
584     }
585
586   this->strtab_->set_string_offsets();
587 }
588
589 // Create the content of the .gnu_incremental_inputs section.
590
591 Output_section_data*
592 Incremental_inputs::create_incremental_inputs_section_data()
593 {
594   switch (parameters->size_and_endianness())
595     {
596 #ifdef HAVE_TARGET_32_LITTLE
597     case Parameters::TARGET_32_LITTLE:
598       return this->sized_create_inputs_section_data<32, false>();
599 #endif
600 #ifdef HAVE_TARGET_32_BIG
601     case Parameters::TARGET_32_BIG:
602       return this->sized_create_inputs_section_data<32, true>();
603 #endif
604 #ifdef HAVE_TARGET_64_LITTLE
605     case Parameters::TARGET_64_LITTLE:
606       return this->sized_create_inputs_section_data<64, false>();
607 #endif
608 #ifdef HAVE_TARGET_64_BIG
609     case Parameters::TARGET_64_BIG:
610       return this->sized_create_inputs_section_data<64, true>();
611 #endif
612     default:
613       gold_unreachable();
614     }
615 }
616
617 // Sized creation of .gnu_incremental_inputs section.
618
619 template<int size, bool big_endian>
620 Output_section_data*
621 Incremental_inputs::sized_create_inputs_section_data()
622 {
623   const int entry_size =
624       Incremental_inputs_entry_write<size, big_endian>::data_size;
625   const int header_size =
626       Incremental_inputs_header_write<size, big_endian>::data_size;
627
628   unsigned int sz = header_size + entry_size * this->inputs_map_.size();
629   unsigned char* buffer = new unsigned char[sz];
630   unsigned char* inputs_base = buffer + header_size;
631
632   Incremental_inputs_header_write<size, big_endian> header_writer(buffer);
633   gold_assert(this->command_line_key_ > 0);
634   int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_);
635
636   header_writer.put_version(INCREMENTAL_LINK_VERSION);
637   header_writer.put_input_file_count(this->inputs_map_.size());
638   header_writer.put_command_line_offset(cmd_offset);
639   header_writer.put_reserved(0);
640
641   for (Inputs_info_map::const_iterator it = this->inputs_map_.begin();
642        it != this->inputs_map_.end();
643        ++it)
644     {
645       gold_assert(it->second.index < this->inputs_map_.size());
646
647       unsigned char* entry_buffer =
648           inputs_base + it->second.index * entry_size;
649       Incremental_inputs_entry_write<size, big_endian> entry(entry_buffer);
650       int filename_offset =
651           this->strtab_->get_offset_from_key(it->second.filename_key);
652       entry.put_filename_offset(filename_offset);
653       switch (it->second.type)
654         {
655         case INCREMENTAL_INPUT_SCRIPT:
656           entry.put_data_offset(0);
657           break;
658         case INCREMENTAL_INPUT_ARCHIVE:
659         case INCREMENTAL_INPUT_OBJECT:
660         case INCREMENTAL_INPUT_SHARED_LIBRARY:
661           // TODO: add per input data.  Currently we store
662           // an out-of-bounds offset for future version of gold to reject
663           // such an incremental_inputs section.
664           entry.put_data_offset(0xffffffff);
665           break;
666         default:
667           gold_unreachable();
668         }
669       // TODO: add per input data and timestamp.  Currently we store
670       // an out-of-bounds offset for future version of gold to reject
671       // such an incremental_inputs section.
672       entry.put_data_offset(0xffffffff);
673       entry.put_timestamp_sec(it->second.mtime.seconds);
674       entry.put_timestamp_nsec(it->second.mtime.nanoseconds);
675       entry.put_input_type(it->second.type);
676       entry.put_reserved(0);
677     }
678
679   return new Output_data_const_buffer(buffer, sz, 8,
680                                       "** incremental link inputs list");
681 }
682
683 // Instantiate the templates we need.
684
685 #ifdef HAVE_TARGET_32_LITTLE
686 template
687 class Sized_incremental_binary<32, false>;
688 #endif
689
690 #ifdef HAVE_TARGET_32_BIG
691 template
692 class Sized_incremental_binary<32, true>;
693 #endif
694
695 #ifdef HAVE_TARGET_64_LITTLE
696 template
697 class Sized_incremental_binary<64, false>;
698 #endif
699
700 #ifdef HAVE_TARGET_64_BIG
701 template
702 class Sized_incremental_binary<64, true>;
703 #endif
704
705 } // End namespace gold.