elfcpp/:
[external/binutils.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 // An object representing the ELF file we edit during an incremental build.
56 // Similar to Object or Dynobj, but operates on Output_file and contains
57 // method specific to file edition (TBD). This is the abstract parent class
58 // implemented in Sized_incremental_binary<size, big_endian> for a specific
59 // endianness and size.
60
61 class Incremental_binary
62 {
63  public:
64   Incremental_binary(Output_file* output, Target* target)
65     : output_(output), target_(target)
66   { }
67
68   virtual
69   ~Incremental_binary()
70   { }
71
72   // Functions and types for the elfcpp::Elf_file interface.  This
73   // permit us to use Incremental_binary as the File template parameter for
74   // elfcpp::Elf_file.
75
76   // The View class is returned by view.  It must support a single
77   // method, data().  This is trivial, because Output_file::get_output_view
78   // does what we need.
79   class View
80   {
81    public:
82     View(const unsigned char* p)
83       : p_(p)
84     { }
85
86     const unsigned char*
87     data() const
88     { return this->p_; }
89
90    private:
91     const unsigned char* p_;
92   };
93
94   // Return a View.
95   View
96   view(off_t file_offset, section_size_type data_size)
97   { return View(this->output_->get_input_view(file_offset, data_size)); }
98
99   // A location in the file.
100   struct Location
101   {
102     off_t file_offset;
103     off_t data_size;
104
105     Location(off_t fo, section_size_type ds)
106       : file_offset(fo), data_size(ds)
107     { }
108
109     Location()
110       : file_offset(0), data_size(0)
111     { }
112   };
113
114   // Get a View given a Location.
115   View view(Location loc)
116   { return View(this->view(loc.file_offset, loc.data_size)); }
117
118   // Report an error.
119   void
120   error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
121
122   // Find the .gnu_incremental_inputs section.  It selects the first section
123   // of type SHT_GNU_INCREMENTAL_INPUTS.  Returns false if such a section
124   // is not found.
125   bool
126   find_incremental_inputs_section(Location* location,
127                                   unsigned int* strtab_shndx)
128   { return do_find_incremental_inputs_section(location, strtab_shndx); }
129
130   // Check the .gnu_incremental_inputs section to see whether an incremental
131   // build is possible.
132   // TODO: on success, should report what files needs to be rebuilt.
133   // INCREMENTAL_INPUTS is used to read the canonical form of the command line
134   // and read the input arguments.  TODO: for items that don't need to be
135   // rebuilt, we should also copy the incremental input information.
136   virtual bool
137   check_inputs(Incremental_inputs* incremental_inputs)
138   { return do_check_inputs(incremental_inputs); }
139
140  protected:
141   // Find incremental inputs section.
142   virtual bool
143   do_find_incremental_inputs_section(Location* location,
144                                      unsigned int* strtab_shndx) = 0;
145
146   // Check the .gnu_incremental_inputs section to see whether an incremental
147   // build is possible.
148   virtual bool
149   do_check_inputs(Incremental_inputs* incremental_inputs) = 0;
150
151  private:
152   // Edited output file object.
153   Output_file* output_;
154   // Target of the output file.
155   Target* target_;
156 };
157
158 template<int size, bool big_endian>
159 class Sized_incremental_binary : public Incremental_binary
160 {
161  public:
162   Sized_incremental_binary(Output_file* output,
163                            const elfcpp::Ehdr<size, big_endian>& ehdr,
164                            Target* target)
165     : Incremental_binary(output, target), elf_file_(this, ehdr)
166   { }
167
168  protected:
169   virtual bool
170   do_find_incremental_inputs_section(Location* location,
171                                      unsigned int* strtab_shndx);
172
173   virtual bool
174   do_check_inputs(Incremental_inputs* incremental_inputs);
175
176  private:
177   // Output as an ELF file.
178   elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file_;
179 };
180
181 // Create an Incremental_binary object for FILE. Returns NULL is this is not
182 // possible, e.g. FILE is not an ELF file or has an unsupported target.
183 Incremental_binary*
184 open_incremental_binary(Output_file* file);
185
186 // Code invoked early during an incremental link that checks what files need
187 // to be relinked.
188 class Incremental_checker
189 {
190  public:
191   // Check if the file named OUTPUT_NAME can be linked incrementally.
192   // INCREMENTAL_INPUTS must have the canonical form of the command line
193   // and input arguments filled - at this point of linking other fields are
194   // probably not filled yet.  TODO: for inputs that don't need to be
195   // rebuilt, this function should fill the incremental input information.
196   Incremental_checker(const char* output_name,
197                       Incremental_inputs* incremental_inputs)
198     : output_name_(output_name), incremental_inputs_(incremental_inputs)
199   { }
200
201   // Analyzes the output file to check if incremental linking is possible and
202   // what files needs to be relinked.
203   bool
204   can_incrementally_link_output_file();
205
206  private:
207   // Name of the output file to analyze.
208   const char* output_name_;
209
210   // The Incremental_inputs object. At this stage of link, only the command
211   // line and inputs are filled.
212   Incremental_inputs* incremental_inputs_;
213 };
214
215 // This class contains the information needed during an incremental
216 // build about the inputs necessary to build the .gnu_incremental_inputs.
217 class Incremental_inputs
218 {
219  public:
220   Incremental_inputs()
221     : lock_(new Lock()), inputs_(NULL), command_line_key_(0),
222       strtab_(new Stringpool())
223   { }
224   ~Incremental_inputs() { delete this->strtab_; }
225
226   // Record the command line.
227   void
228   report_command_line(int argc, const char* const* argv);
229
230   // Record the input arguments obtained from parsing the command line.
231   void
232   report_inputs(const Input_arguments& inputs)
233   { this->inputs_ = &inputs; }
234
235   // Record that the input argument INPUT is an archive ARCHIVE.
236   void
237   report_archive(const Input_argument* input, Archive* archive);
238
239   // Record that the input argument INPUT is to an object OBJ.
240   void
241   report_object(const Input_argument* input, Object* obj);
242
243   // Record that the input argument INPUT is to an script SCRIPT.
244   void
245   report_script(const Input_argument* input, Timespec mtime,
246                 Script_info* script);
247
248   // Prepare for layout.  Called from Layout::finalize.
249   void
250   finalize();
251
252   // Create the content of the .gnu_incremental_inputs section.
253   Output_section_data*
254   create_incremental_inputs_section_data();
255
256   // Return the .gnu_incremental_strtab stringpool.
257   Stringpool*
258   get_stringpool()
259   { return this->strtab_; }
260
261   // Return the canonical form of the command line, as will be stored in
262   // .gnu_incremental_strtab.
263   const std::string&
264   command_line()
265   { return this->command_line_; }
266
267   // Return the input files found in the command line.
268   const Input_arguments*
269   inputs()
270   { return this->inputs_; }
271
272  private:
273   // Code for each of the four possible variants of create_inputs_section_data.
274   template<int size, bool big_endian>
275   Output_section_data*
276   sized_create_inputs_section_data();
277
278   // Compute indexes in the order in which the inputs should appear in
279   // .gnu_incremental_inputs and put file names to the stringtable.
280   // This needs to be done after all the scripts are parsed.
281
282   void
283   finalize_inputs(Input_argument_list::const_iterator begin,
284                   Input_argument_list::const_iterator end,
285                   unsigned int* index);
286
287   // Additional data about an input needed for an incremental link.
288   // None of these pointers is owned by the structure.
289   struct Input_info
290   {
291     Input_info()
292       : type(INCREMENTAL_INPUT_INVALID), archive(NULL), filename_key(0),
293         index(0)
294     { }
295
296     // Type of the file pointed by this argument.
297     Incremental_input_type type;
298
299     union
300     {
301       // Present if type == INCREMENTAL_INPUT_ARCHIVE.
302       Archive* archive;
303
304       // Present if type == INCREMENTAL_INPUT_OBJECT or
305       // INCREMENTAL_INPUT_SHARED_LIBRARY.
306       Object* object;
307
308       // Present if type == INCREMENTAL_INPUT_SCRIPT.
309       Script_info* script;
310     };
311
312     // Key of the filename string in the section stringtable.
313     Stringpool::Key filename_key;
314
315     // Position of the entry information in the output section.
316     unsigned int index;
317
318     // Last modification time of the file.
319     Timespec mtime;
320   };
321
322   typedef std::map<const Input_argument*, Input_info> Inputs_info_map;
323
324   // A lock guarding access to inputs_ during the first phase of linking, when
325   // report_ function may be called from multiple threads.
326   Lock* lock_;
327
328   // The list of input arguments obtained from parsing the command line.
329   const Input_arguments* inputs_;
330
331   // A map containing additional information about the input elements.
332   Inputs_info_map inputs_map_;
333
334   // Canonical form of the command line, as will be stored in
335   // .gnu_incremental_strtab.
336   std::string command_line_;
337
338   // The key of the command line string in the string pool.
339   Stringpool::Key command_line_key_;
340
341   // The .gnu_incremental_strtab string pool associated with the
342   // .gnu_incremental_inputs.
343   Stringpool* strtab_;
344 };
345
346 } // End namespace gold.
347
348 #endif // !defined(GOLD_INCREMENTAL_H)