2009-12-07 Rafael Avila de Espindola <espindola@google.com>
[external/binutils.git] / gold / incremental-dump.cc
1 // inremental.cc -- incremental linking test/deubg tool
2
3 // Copyright 2009 Free Software Foundation, Inc.
4 // Written by Rafael Avila de Espindola <rafael.espindola@gmail.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
24 // This file is a (still incomplete) test/debug tool that should display
25 // all information available in the incremental linking sections in a
26 // format that is easy to read.
27 // Once the format is a bit more stable, this should probably be moved to
28 // readelf. Because of that, the use of gold's data structures and functions
29 // is just a short term convenience and not a design decision.
30
31 #include "gold.h"
32
33 #include <stdio.h>
34 #include <errno.h>
35
36 #include "incremental.h"
37
38 namespace gold
39 {
40   class Output_file;
41 }
42
43 using namespace gold;
44
45 template<int size, bool big_endian>
46 static void
47 dump_incremental_inputs(const char* argv0,
48                         const char* filename, Incremental_binary* inc)
49 {
50   bool t;
51   unsigned int strtab_shndx;
52   Incremental_binary::Location location;
53
54   t = inc->find_incremental_inputs_section(&location, &strtab_shndx);
55   if (!t)
56     {
57       fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0,
58               filename);
59       exit (1);
60     }
61
62   Incremental_binary::View inputs_view(inc->view(location));
63   const unsigned char* p = inputs_view.data();
64
65   Incremental_inputs_header<size, big_endian> incremental_header(p);
66
67   const unsigned char* incremental_inputs_base =
68     (p + sizeof(Incremental_inputs_header_data));
69
70   if (incremental_header.get_version() != 1)
71     {
72       fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0,
73               filename, incremental_header.get_version());
74       exit(1);
75     }
76
77   elfcpp::Elf_file<size, big_endian, Incremental_binary> elf_file(inc);
78
79   if (elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB)
80     {
81       fprintf(stderr,
82               "%s: %s: invalid string table section %u (type %d != %d)\n",
83               argv0, filename, strtab_shndx,
84               elf_file.section_type(strtab_shndx), elfcpp::SHT_STRTAB);
85       exit(1);
86     }
87
88   Incremental_binary::Location
89     strtab_location(elf_file.section_contents(strtab_shndx));
90
91   Incremental_binary::View strtab_view(inc->view(strtab_location));
92   p = strtab_view.data();
93
94   elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size);
95   const char* command_line;
96   elfcpp::Elf_Word command_line_offset =
97     incremental_header.get_command_line_offset();
98   t = strtab.get_c_string(command_line_offset, &command_line);
99
100   if (!t)
101     {
102       fprintf(stderr,
103               "%s: %s: failed to get link command line: %zu out of range\n",
104               argv0, filename,
105               static_cast<size_t>(command_line_offset));
106       exit(1);
107     }
108
109   printf("Link command line: %s\n", command_line);
110
111   printf("Input files:\n");
112   for (unsigned i = 0; i < incremental_header.get_input_file_count(); ++i)
113     {
114       const unsigned char* input_p = incremental_inputs_base +
115         i * sizeof(Incremental_inputs_entry_data);
116       Incremental_inputs_entry<size, big_endian> input(input_p);
117       const char* objname;
118
119       t = strtab.get_c_string(input.get_filename_offset(), &objname);
120       if (!t)
121         {
122           fprintf(stderr,"%s: %s: failed to get file name for object %u:"
123                   " %zu out of range\n", argv0, filename, i,
124                   static_cast<size_t>(input.get_filename_offset()));
125           exit(1);
126         }
127       printf("  %s\n", objname);
128       printf("    Timestamp sec = %llu\n",
129              static_cast<unsigned long long>(input.get_timestamp_sec()));
130       printf("    Timestamp nsec = %d\n", input.get_timestamp_nsec());
131       printf("    Type = ");
132       // TODO: print the data at input->data_offset once we have it.
133       elfcpp::Elf_Word input_type = input.get_input_type();
134       switch (input_type)
135       {
136       case INCREMENTAL_INPUT_OBJECT:
137         printf("Object\n");
138         break;
139       case INCREMENTAL_INPUT_ARCHIVE:
140         printf("Archive\n");
141         break;
142       case INCREMENTAL_INPUT_SHARED_LIBRARY:
143         printf("Shared library\n");
144         break;
145       case INCREMENTAL_INPUT_SCRIPT:
146         printf("Linker script\n");
147         if (input.get_data_offset() != 0)
148           {
149             fprintf(stderr,"%s: %s: %u is a script but offset is not zero",
150                     argv0, filename, i);
151             exit(1);
152           }
153         break;
154       case INCREMENTAL_INPUT_INVALID:
155       default:
156         fprintf(stderr, "%s: invalid file type for object %u: %d\n",
157                 argv0, i, input_type);
158         exit(1);
159       }
160     }
161 }
162
163 int
164 main(int argc, char** argv)
165 {
166   if (argc != 2)
167     {
168       fprintf(stderr, "Usage: %s <file>\n", argv[0]);
169       return 1;
170     }
171   const char* filename = argv[1];
172
173   Output_file* file = new Output_file(filename);
174
175   bool t = file->open_for_modification();
176   if (!t)
177     {
178       fprintf(stderr, "%s: open_for_modification(%s): %s\n", argv[0], filename,
179               strerror(errno));
180       return 1;
181     }
182
183   Incremental_binary* inc = open_incremental_binary(file);
184
185   if (inc == NULL)
186     {
187       fprintf(stderr, "%s: open_incremental_binary(%s): %s\n", argv[0],
188               filename, strerror(errno));
189       return 1;
190     }
191
192   switch (parameters->size_and_endianness())
193     {
194 #ifdef HAVE_TARGET_32_LITTLE
195     case Parameters::TARGET_32_LITTLE:
196       dump_incremental_inputs<32, false>(argv[0], filename, inc);
197       break;
198 #endif
199 #ifdef HAVE_TARGET_32_BIG
200     case Parameters::TARGET_32_BIG:
201       dump_incremental_inputs<32, true>(argv[0], filename, inc);
202       break;
203 #endif
204 #ifdef HAVE_TARGET_64_LITTLE
205     case Parameters::TARGET_64_LITTLE:
206       dump_incremental_inputs<64, false>(argv[0], filename, inc);
207       break;
208 #endif
209 #ifdef HAVE_TARGET_64_BIG
210     case Parameters::TARGET_64_BIG:
211       dump_incremental_inputs<64, true>(argv[0], filename, inc);
212       break;
213 #endif
214     default:
215       gold_unreachable();
216     }
217
218   return 0;
219 }