OSDN Git Service

a94f39719c961c864880aa515a2c423357eb62dd
[pf3gnuchains/pf3gnuchains4x.git] / gold / incremental.h
1 // inremental.h -- incremental linking support for gold   -*- C++ -*-
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 #ifndef GOLD_INCREMENTAL_H
24 #define GOLD_INCREMENTAL_H
25
26 #include <map>
27 #include <vector>
28
29 #include "elfcpp_file.h"
30 #include "stringpool.h"
31 #include "workqueue.h"
32 #include "fileread.h"
33 #include "output.h"
34
35 namespace gold
36 {
37
38 class Archive;
39 class Input_argument;
40 class Incremental_inputs_checker;
41 class Object;
42 class Output_section_data;
43
44 // Incremental input type as stored in .gnu_incremental_inputs.
45
46 enum Incremental_input_type
47 {
48   INCREMENTAL_INPUT_INVALID = 0,
49   INCREMENTAL_INPUT_OBJECT = 1,
50   INCREMENTAL_INPUT_ARCHIVE = 2,
51   INCREMENTAL_INPUT_SHARED_LIBRARY = 3,
52   INCREMENTAL_INPUT_SCRIPT = 4
53 };
54
55 // Header of the .gnu_incremental_input section.
56 struct Incremental_inputs_header_data
57 {
58   // Incremental linker version.
59   elfcpp::Elf_Word version;
60
61   // Numer of input files in the link.
62   elfcpp::Elf_Word input_file_count;
63
64   // Offset of command line options in .gnu_incremental_strtab.
65   elfcpp::Elf_Word command_line_offset;
66
67   // Padding.
68   elfcpp::Elf_Word reserved;
69 };
70
71 // Reader class for .gnu_incremental_inputs header. See
72 // Incremental_inputs_header_data for fields descriptions.
73
74 template<int size, bool big_endian>
75 class Incremental_inputs_header
76 {
77  private:
78   typedef Incremental_inputs_header_data Data_type;
79   typedef elfcpp::Convert<32, big_endian> Convert32;
80
81  public:
82   Incremental_inputs_header(const unsigned char *p)
83     : p_(reinterpret_cast<const Data_type*>(p))
84   { }
85
86   static const int data_size = sizeof(Data_type);
87
88   elfcpp::Elf_Word
89   get_version() const
90   { return Convert32::convert_host(this->p_->version); }
91
92   elfcpp::Elf_Word
93   get_input_file_count() const
94   { return Convert32::convert_host(this->p_->input_file_count); }
95
96   elfcpp::Elf_Word
97   get_command_line_offset() const
98   { return Convert32::convert_host(this->p_->command_line_offset); }
99
100   elfcpp::Elf_Word
101   get_reserved() const
102   { return Convert32::convert_host(this->p_->reserved); }
103
104  private:
105   const Data_type* p_;
106 };
107
108 // Writer class for .gnu_incremental_inputs header. See
109 // Incremental_inputs_header_data for fields descriptions.
110
111 template<int size, bool big_endian>
112 class Incremental_inputs_header_write
113 {
114  private:
115   typedef Incremental_inputs_header_data Data_type;
116   typedef elfcpp::Convert<32, big_endian> Convert32;
117
118  public:
119   Incremental_inputs_header_write(unsigned char *p)
120     : p_(reinterpret_cast<Data_type*>(p))
121   { }
122
123   static const int data_size = sizeof(Data_type);
124
125   void
126   put_version(elfcpp::Elf_Word v)
127   { this->p_->version = Convert32::convert_host(v); }
128
129   void
130   put_input_file_count(elfcpp::Elf_Word v)
131   { this->p_->input_file_count = Convert32::convert_host(v); }
132
133   void
134   put_command_line_offset(elfcpp::Elf_Word v)
135   { this->p_->command_line_offset = Convert32::convert_host(v); }
136
137   void
138   put_reserved(elfcpp::Elf_Word v)
139   { this->p_->reserved = Convert32::convert_host(v); }
140
141  private:
142   Data_type* p_;
143 };
144
145 // Data stored in .gnu_incremental_input after the header for each of the
146 // Incremental_input_header_data::input_file_count input entries.
147 struct Incremental_inputs_entry_data
148 {
149   // Offset of file name in .gnu_incremental_strtab section.
150   elfcpp::Elf_Word filename_offset;
151
152   // Offset of data in .gnu_incremental_input.
153   elfcpp::Elf_Word data_offset;
154
155   // Timestamp (in seconds).
156   elfcpp::Elf_Xword timestamp_sec;
157
158   // Nano-second part of timestamp (if supported).
159   elfcpp::Elf_Word timestamp_nsec;
160
161   // Type of the input entry.
162   elfcpp::Elf_Half input_type;
163
164   // Padding.
165   elfcpp::Elf_Half reserved;
166 };
167
168 // Reader class for an .gnu_incremental_inputs entry. See
169 // Incremental_inputs_entry_data for fields descriptions.
170 template<int size, bool big_endian>
171 class Incremental_inputs_entry
172 {
173  private:
174   typedef Incremental_inputs_entry_data Data_type;
175   typedef elfcpp::Convert<32, big_endian> Convert32;
176   typedef elfcpp::Convert<64, big_endian> Convert64;
177
178  public:
179   Incremental_inputs_entry(const unsigned char *p)
180     : p_(reinterpret_cast<const Data_type*>(p))
181   { }
182
183   static const int data_size = sizeof(Data_type);
184
185   elfcpp::Elf_Word
186   get_filename_offset()
187   { return Convert32::convert_host(this->p_->filename_offset); }
188
189   elfcpp::Elf_Word
190   get_data_offset()
191   { return Convert32::convert_host(this->p_->data_offset); }
192
193   elfcpp::Elf_Xword
194   get_timestamp_sec()
195   { return Convert64::convert_host(this->p_->timestamp_sec); }
196
197   elfcpp::Elf_Word
198   get_timestamp_nsec()
199   { return Convert32::convert_host(this->p_->timestamp_nsec); }
200
201   elfcpp::Elf_Word
202   get_input_type()
203   { return Convert32::convert_host(this->p_->input_type); }
204
205   elfcpp::Elf_Word
206   get_reserved()
207   { return Convert32::convert_host(this->p_->reserved); }
208
209  private:
210   const Data_type* p_;
211 };
212
213 // Writer class for an .gnu_incremental_inputs entry. See
214 // Incremental_inputs_entry_data for fields descriptions.
215 template<int size, bool big_endian>
216 class Incremental_inputs_entry_write
217 {
218  private:
219   typedef Incremental_inputs_entry_data Data_type;
220   typedef elfcpp::Convert<32, big_endian> Convert32;
221   typedef elfcpp::Convert<64, big_endian> Convert64;
222
223  public:
224   Incremental_inputs_entry_write(unsigned char *p)
225     : p_(reinterpret_cast<Data_type*>(p))
226   { }
227
228   static const int data_size = sizeof(Data_type);
229
230   void
231   put_filename_offset(elfcpp::Elf_Word v)
232   { this->p_->filename_offset = Convert32::convert_host(v); }
233
234   void
235   put_data_offset(elfcpp::Elf_Word v)
236   { this->p_->data_offset = Convert32::convert_host(v); }
237
238   void
239   put_timestamp_sec(elfcpp::Elf_Xword v)
240   { this->p_->timestamp_sec = Convert64::convert_host(v); }
241
242   void
243   put_timestamp_nsec(elfcpp::Elf_Word v)
244   { this->p_->timestamp_nsec = Convert32::convert_host(v); }
245
246   void
247   put_input_type(elfcpp::Elf_Word v)
248   { this->p_->input_type = Convert32::convert_host(v); }
249
250   void
251   put_reserved(elfcpp::Elf_Word v)
252   { this->p_->reserved = Convert32::convert_host(v); }
253
254  private:
255   Data_type* p_;
256 };
257
258 // An object representing the ELF file we edit during an incremental build.
259 // Similar to Object or Dynobj, but operates on Output_file and contains
260 // method specific to file edition (TBD). This is the abstract parent class
261 // implemented in Sized_incremental_binary<size, big_endian> for a specific
262 // endianness and size.
263
264 class Incremental_binary
265 {
266  public:
267   Incremental_binary(Output_file* output, Target* target)
268     : output_(output), target_(target)
269   { }
270
271   virtual
272   ~Incremental_binary()
273   { }
274
275   // Functions and types for the elfcpp::Elf_file interface.  This
276   // permit us to use Incremental_binary as the File template parameter for
277   // elfcpp::Elf_file.
278
279   // The View class is returned by view.  It must support a single
280   // method, data().  This is trivial, because Output_file::get_output_view
281   // does what we need.
282   class View
283   {
284    public:
285     View(const unsigned char* p)
286       : p_(p)
287     { }
288
289     const unsigned char*
290     data() const
291     { return this->p_; }
292
293    private:
294     const unsigned char* p_;
295   };
296
297   // Return a View.
298   View
299   view(off_t file_offset, section_size_type data_size)
300   { return View(this->output_->get_input_view(file_offset, data_size)); }
301
302   // A location in the file.
303   struct Location
304   {
305     off_t file_offset;
306     off_t data_size;
307
308     Location(off_t fo, section_size_type ds)
309       : file_offset(fo), data_size(ds)
310     { }
311
312     Location()
313       : file_offset(0), data_size(0)
314     { }
315   };
316
317   // Get a View given a Location.
318   View view(Location loc)
319   { return View(this->view(loc.file_offset, loc.data_size)); }
320
321   // Report an error.
322   void
323   error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
324
325   // Find the .gnu_incremental_inputs section.  It selects the first section
326   // of type SHT_GNU_INCREMENTAL_INPUTS.  Returns false if such a section
327   // is not found.
328   bool
329   find_incremental_inputs_section(Location* location,
330                                   unsigned int* strtab_shndx)
331   { return do_find_incremental_inputs_section(location, strtab_shndx); }
332
333   // Check the .gnu_incremental_inputs section to see whether an incremental
334   // build is possible.
335   // TODO: on success, should report what files needs to be rebuilt.
336   // INCREMENTAL_INPUTS is used to read the canonical form of the command line
337   // and read the input arguments.  TODO: for items that don't need to be
338   // rebuilt, we should also copy the incremental input information.
339   virtual bool
340   check_inputs(Incremental_inputs* incremental_inputs)
341   { return do_check_inputs(incremental_inputs); }
342
343  protected:
344   // Find incremental inputs section.
345   virtual bool
346   do_find_incremental_inputs_section(Location* location,
347                                      unsigned int* strtab_shndx) = 0;
348
349   // Check the .gnu_incremental_inputs section to see whether an incremental
350   // build is possible.
351   virtual bool
352   do_check_inputs(Incremental_inputs* incremental_inputs) = 0;
353
354  private:
355   // Edited output file object.
356   Output_file* output_;
357   // Target of the output file.
358   Target* target_;
359 };
360
361 template<int size, bool big_endian>
362 class Sized_incremental_binary : public Incremental_binary
363 {
364  public:
365   Sized_incremental_binary(Output_file* output,
366                            const elfcpp::Ehdr<size, big_endian>& ehdr,
367                            Target* target)
368     : Incremental_binary(output, target), elf_file_(this, ehdr)
369   { }
370
371  protected:
372   virtual bool
373   do_find_incremental_inputs_section(Location* location,
374                                      unsigned int* strtab_shndx);
375
376   virtual bool
377   do_check_inputs(Incremental_inputs* incremental_inputs);
378
379  private:
380   // Output as an ELF file.
381   elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
382 };
383
384 // Create an Incremental_binary object for FILE. Returns NULL is this is not
385 // possible, e.g. FILE is not an ELF file or has an unsupported target.
386 Incremental_binary*
387 open_incremental_binary(Output_file* file);
388
389 // Code invoked early during an incremental link that checks what files need
390 // to be relinked.
391 class Incremental_checker
392 {
393  public:
394   // Check if the file named OUTPUT_NAME can be linked incrementally.
395   // INCREMENTAL_INPUTS must have the canonical form of the command line
396   // and input arguments filled - at this point of linking other fields are
397   // probably not filled yet.  TODO: for inputs that don't need to be
398   // rebuilt, this function should fill the incremental input information.
399   Incremental_checker(const char* output_name,
400                       Incremental_inputs* incremental_inputs)
401     : output_name_(output_name), incremental_inputs_(incremental_inputs)
402   { }
403
404   // Analyzes the output file to check if incremental linking is possible and
405   // what files needs to be relinked.
406   bool
407   can_incrementally_link_output_file();
408
409  private:
410   // Name of the output file to analyze.
411   const char* output_name_;
412
413   // The Incremental_inputs object. At this stage of link, only the command
414   // line and inputs are filled.
415   Incremental_inputs* incremental_inputs_;
416 };
417
418 // This class contains the information needed during an incremental
419 // build about the inputs necessary to build the .gnu_incremental_inputs.
420 class Incremental_inputs
421 {
422  public:
423   Incremental_inputs()
424     : lock_(new Lock()), inputs_(NULL), command_line_key_(0),
425       strtab_(new Stringpool())
426   { }
427   ~Incremental_inputs() { delete this->strtab_; }
428
429   // Record the command line.
430   void
431   report_command_line(int argc, const char* const* argv);
432
433   // Record the input arguments obtained from parsing the command line.
434   void
435   report_inputs(const Input_arguments& inputs)
436   { this->inputs_ = &inputs; }
437
438   // Record that the input argument INPUT is an archive ARCHIVE.
439   void
440   report_archive(const Input_argument* input, Archive* archive);
441
442   // Record that the input argument INPUT is to an object OBJ.
443   void
444   report_object(const Input_argument* input, Object* obj);
445
446   // Record that the input argument INPUT is to an script SCRIPT.
447   void
448   report_script(const Input_argument* input, Timespec mtime,
449                 Script_info* script);
450
451   // Prepare for layout.  Called from Layout::finalize.
452   void
453   finalize();
454
455   // Create the content of the .gnu_incremental_inputs section.
456   Output_section_data*
457   create_incremental_inputs_section_data();
458
459   // Return the .gnu_incremental_strtab stringpool.
460   Stringpool*
461   get_stringpool()
462   { return this->strtab_; }
463
464   // Return the canonical form of the command line, as will be stored in
465   // .gnu_incremental_strtab.
466   const std::string&
467   command_line()
468   { return this->command_line_; }
469
470   // Return the input files found in the command line.
471   const Input_arguments*
472   inputs()
473   { return this->inputs_; }
474
475  private:
476   // Code for each of the four possible variants of create_inputs_section_data.
477   template<int size, bool big_endian>
478   Output_section_data*
479   sized_create_inputs_section_data();
480
481   // Compute indexes in the order in which the inputs should appear in
482   // .gnu_incremental_inputs and put file names to the stringtable.
483   // This needs to be done after all the scripts are parsed.
484
485   void
486   finalize_inputs(Input_argument_list::const_iterator begin,
487                   Input_argument_list::const_iterator end,
488                   unsigned int* index);
489
490   // Additional data about an input needed for an incremental link.
491   // None of these pointers is owned by the structure.
492   struct Input_info
493   {
494     Input_info()
495       : type(INCREMENTAL_INPUT_INVALID), archive(NULL), filename_key(0),
496         index(0)
497     { }
498
499     // Type of the file pointed by this argument.
500     Incremental_input_type type;
501
502     union
503     {
504       // Present if type == INCREMENTAL_INPUT_ARCHIVE.
505       Archive* archive;
506
507       // Present if type == INCREMENTAL_INPUT_OBJECT or
508       // INCREMENTAL_INPUT_SHARED_LIBRARY.
509       Object* object;
510
511       // Present if type == INCREMENTAL_INPUT_SCRIPT.
512       Script_info* script;
513     };
514
515     // Key of the filename string in the section stringtable.
516     Stringpool::Key filename_key;
517
518     // Position of the entry information in the output section.
519     unsigned int index;
520
521     // Last modification time of the file.
522     Timespec mtime;
523   };
524
525   typedef std::map<const Input_argument*, Input_info> Inputs_info_map;
526
527   // A lock guarding access to inputs_ during the first phase of linking, when
528   // report_ function may be called from multiple threads.
529   Lock* lock_;
530
531   // The list of input arguments obtained from parsing the command line.
532   const Input_arguments* inputs_;
533
534   // A map containing additional information about the input elements.
535   Inputs_info_map inputs_map_;
536
537   // Canonical form of the command line, as will be stored in
538   // .gnu_incremental_strtab.
539   std::string command_line_;
540
541   // The key of the command line string in the string pool.
542   Stringpool::Key command_line_key_;
543
544   // The .gnu_incremental_strtab string pool associated with the
545   // .gnu_incremental_inputs.
546   Stringpool* strtab_;
547 };
548
549 } // End namespace gold.
550
551 #endif // !defined(GOLD_INCREMENTAL_H)