]> Git Repo - binutils.git/blob - libctf/ctf-link.c
libctf: add the ctf_link machinery
[binutils.git] / libctf / ctf-link.c
1 /* CTF linking.
2    Copyright (C) 2019 Free Software Foundation, Inc.
3
4    This file is part of libctf.
5
6    libctf is free software; you can redistribute it and/or modify it under
7    the terms of the GNU General Public License as published by the Free
8    Software Foundation; either version 3, or (at your option) any later
9    version.
10
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14    See the GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; see the file COPYING.  If not see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <ctf-impl.h>
21 #include <string.h>
22
23 /* Linker machinery.
24
25    CTF linking consists of adding CTF archives full of content to be merged into
26    this one to the current file (which must be writable) by calling
27    ctf_link_add_ctf().  Once this is done, a call to ctf_link() will merge the
28    type tables together, generating new CTF files as needed, with this one as a
29    parent, to contain types from the inputs which conflict.
30    ctf_link_add_strtab() takes a callback which provides string/offset pairs to
31    be added to the external symbol table and deduplicated from all CTF string
32    tables in the output link; ctf_link_shuffle_syms() takes a callback which
33    provides symtab entries in ascending order, and shuffles the function and
34    data sections to match; and ctf_link_write() emits a CTF file (if there are
35    no conflicts requiring per-compilation-unit sub-CTF files) or CTF archives
36    (otherwise) and returns it, suitable for addition in the .ctf section of the
37    output.  */
38
39 /* Add a file to a link.  */
40
41 static void ctf_arc_close_thunk (void *arc)
42 {
43   ctf_arc_close ((ctf_archive_t *) arc);
44 }
45
46 static void ctf_file_close_thunk (void *file)
47 {
48   ctf_file_close ((ctf_file_t *) file);
49 }
50
51 int
52 ctf_link_add_ctf (ctf_file_t *fp, ctf_archive_t *ctf, const char *name)
53 {
54   char *dupname = NULL;
55
56   if (fp->ctf_link_outputs)
57     return (ctf_set_errno (fp, ECTF_LINKADDEDLATE));
58   if (fp->ctf_link_inputs == NULL)
59     fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string,
60                                               ctf_hash_eq_string, free,
61                                               ctf_arc_close_thunk);
62
63   if (fp->ctf_link_inputs == NULL)
64     goto oom;
65
66   if ((dupname = strdup (name)) == NULL)
67     goto oom;
68
69   if (ctf_dynhash_insert (fp->ctf_link_inputs, dupname, ctf) < 0)
70     goto oom;
71
72   return 0;
73  oom:
74   free (fp->ctf_link_inputs);
75   fp->ctf_link_inputs = NULL;
76   free (dupname);
77   return (ctf_set_errno (fp, ENOMEM));
78 }
79
80 typedef struct ctf_link_in_member_cb_arg
81 {
82   ctf_file_t *out_fp;
83   const char *file_name;
84   ctf_file_t *in_fp;
85   ctf_file_t *main_input_fp;
86   const char *cu_name;
87   char *arcname;
88   int done_main_member;
89   int share_mode;
90   int in_input_cu_file;
91 } ctf_link_in_member_cb_arg_t;
92
93 /* Link one type into the link.  We rely on ctf_add_type() to detect
94    duplicates.  This is not terribly reliable yet (unnmamed types will be
95    mindlessly duplicated), but will improve shortly.  */
96
97 static int
98 ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_)
99 {
100   ctf_link_in_member_cb_arg_t *arg = (ctf_link_in_member_cb_arg_t *) arg_;
101   ctf_file_t *per_cu_out_fp;
102   int err;
103
104   if (arg->share_mode != CTF_LINK_SHARE_UNCONFLICTED)
105     {
106       ctf_dprintf ("Share-duplicated mode not yet implemented.\n");
107       return ctf_set_errno (arg->out_fp, ECTF_NOTYET);
108     }
109
110   /* Simply call ctf_add_type: if it reports a conflict and we're adding to the
111      main CTF file, add to the per-CU archive member instead, creating it if
112      necessary.  If we got this type from a per-CU archive member, add it
113      straight back to the corresponding member in the output.  */
114
115   if (!arg->in_input_cu_file)
116     {
117       if (ctf_add_type (arg->out_fp, arg->in_fp, type) != CTF_ERR)
118         return 0;
119
120       err = ctf_errno (arg->out_fp);
121       if (err != ECTF_CONFLICT)
122         {
123           ctf_dprintf ("Cannot link type %lx from archive member %s, input file %s "
124                        "into output link: %s\n", type, arg->arcname, arg->file_name,
125                        ctf_errmsg (err));
126           return -1;
127         }
128       ctf_set_errno (arg->out_fp, 0);
129     }
130
131   if ((per_cu_out_fp = ctf_dynhash_lookup (arg->out_fp->ctf_link_outputs,
132                                            arg->arcname)) == NULL)
133     {
134       int err;
135
136       if ((per_cu_out_fp = ctf_create (&err)) == NULL)
137         {
138           ctf_dprintf ("Cannot create per-CU CTF archive for member %s: %s\n",
139                        arg->arcname, ctf_errmsg (err));
140           ctf_set_errno (arg->out_fp, err);
141           return -1;
142         }
143
144       if (ctf_dynhash_insert (arg->out_fp->ctf_link_outputs, arg->arcname,
145                               per_cu_out_fp) < 0)
146         {
147           ctf_set_errno (arg->out_fp, ENOMEM);
148           return -1;
149         }
150
151       ctf_import (per_cu_out_fp, arg->out_fp);
152       ctf_cuname_set (per_cu_out_fp, arg->cu_name);
153     }
154
155   if (ctf_add_type (per_cu_out_fp, arg->in_fp, type) != CTF_ERR)
156     return 0;
157
158   err = ctf_errno (per_cu_out_fp);
159   if (err == ECTF_CONFLICT)
160       /* Conflicts are possible at this stage only if a non-ld user has combined
161          multiple TUs into a single output dictionary.  Even in this case we do not
162          want to stop the link or propagate the error.  */
163       ctf_set_errno (arg->out_fp, 0);
164
165   return 0;                                     /* As above: do not lose types.  */
166 }
167
168 /* Merge every type and variable in this archive member into the link, so we can
169    relink things that have already had ld run on them.  We use the archive
170    member name, sans any leading '.ctf.', as the CU name for ambiguous types if
171    there is one and it's not the default: otherwise, we use the name of the
172    input file.  */
173 static int
174 ctf_link_one_input_archive_member (ctf_file_t *in_fp, const char *name, void *arg_)
175 {
176   ctf_link_in_member_cb_arg_t *arg = (ctf_link_in_member_cb_arg_t *) arg_;
177   int err = 0;
178
179   if (strcmp (name, _CTF_SECTION) == 0)
180     {
181       /* This file is the default member of this archive, and has already been
182          explicitly processed.
183
184          In the default sharing mode of CTF_LINK_SHARE_UNCONFLICTED, it does no
185          harm to rescan an existing shared repo again: all the types will just
186          end up in the same place.  But in CTF_LINK_SHARE_DUPLICATED mode, this
187          causes the system to erroneously conclude that all types are duplicated
188          and should be shared, even if they are not.  */
189
190       if (arg->done_main_member)
191         return 0;
192       arg->arcname = strdup (".ctf.");
193       if (arg->arcname)
194         {
195           char *new_name;
196
197           new_name = ctf_str_append (arg->arcname, arg->file_name);
198           if (new_name)
199             arg->arcname = new_name;
200           else
201             free (arg->arcname);
202         }
203     }
204   else
205     {
206       arg->arcname = strdup (name);
207
208       /* Get ambiguous types from our parent.  */
209       ctf_import (in_fp, arg->main_input_fp);
210       arg->in_input_cu_file = 1;
211     }
212
213   if (!arg->arcname)
214     return ctf_set_errno (in_fp, ENOMEM);
215
216   arg->cu_name = name;
217   if (strncmp (arg->cu_name, ".ctf.", strlen (".ctf.")) == 0)
218     arg->cu_name += strlen (".ctf.");
219   arg->in_fp = in_fp;
220
221   err = ctf_type_iter_all (in_fp, ctf_link_one_type, arg);
222
223   arg->in_input_cu_file = 0;
224   free (arg->arcname);
225
226   if (err < 0)
227       return -1;                                /* Errno is set for us.  */
228
229   return 0;
230 }
231
232 /* Link one input file's types into the output file.  */
233 static void
234 ctf_link_one_input_archive (void *key, void *value, void *arg_)
235 {
236   const char *file_name = (const char *) key;
237   ctf_archive_t *arc = (ctf_archive_t *) value;
238   ctf_link_in_member_cb_arg_t *arg = (ctf_link_in_member_cb_arg_t *) arg_;
239   int err;
240
241   arg->file_name = file_name;
242   arg->done_main_member = 0;
243   if ((arg->main_input_fp = ctf_arc_open_by_name (arc, NULL, &err)) == NULL)
244     if (err != ECTF_ARNNAME)
245       {
246         ctf_dprintf ("Cannot open main archive member in input file %s in the "
247                      "link: skipping: %s.\n", arg->file_name,
248                      ctf_errmsg (err));
249         return;
250       }
251
252   if (ctf_link_one_input_archive_member (arg->main_input_fp,
253                                          _CTF_SECTION, arg) < 0)
254     {
255       ctf_file_close (arg->main_input_fp);
256       return;
257     }
258   arg->done_main_member = 1;
259   if (ctf_archive_iter (arc, ctf_link_one_input_archive_member, arg) < 0)
260     ctf_dprintf ("Cannot traverse archive in input file %s: link "
261                  "cannot continue: %s.\n", arg->file_name,
262                  ctf_errmsg (ctf_errno (arg->out_fp)));
263   else
264     {
265       /* The only error indication to the caller is the errno: so ensure that it
266          is zero if there was no actual error from the caller.  */
267       ctf_set_errno (arg->out_fp, 0);
268     }
269   ctf_file_close (arg->main_input_fp);
270 }
271
272 /* Merge types and variable sections in all files added to the link
273    together.  */
274 int
275 ctf_link (ctf_file_t *fp, int share_mode)
276 {
277   ctf_link_in_member_cb_arg_t arg;
278
279   memset (&arg, 0, sizeof (struct ctf_link_in_member_cb_arg));
280   arg.out_fp = fp;
281   arg.share_mode = share_mode;
282
283   if (fp->ctf_link_inputs == NULL)
284     return 0;                                   /* Nothing to do. */
285
286   if (fp->ctf_link_outputs == NULL)
287     fp->ctf_link_outputs = ctf_dynhash_create (ctf_hash_string,
288                                                ctf_hash_eq_string, free,
289                                                ctf_file_close_thunk);
290
291   if (fp->ctf_link_outputs == NULL)
292     return ctf_set_errno (fp, ENOMEM);
293
294   ctf_dynhash_iter (fp->ctf_link_inputs, ctf_link_one_input_archive,
295                     &arg);
296
297   if (ctf_errno (fp) != 0)
298     return -1;
299   return 0;
300 }
301
302 typedef struct ctf_link_out_string_cb_arg
303 {
304   const char *str;
305   uint32_t offset;
306   int err;
307 } ctf_link_out_string_cb_arg_t;
308
309 /* Intern a string in the string table of an output per-CU CTF file.  */
310 static void
311 ctf_link_intern_extern_string (void *key _libctf_unused_, void *value,
312                                void *arg_)
313 {
314   ctf_file_t *fp = (ctf_file_t *) value;
315   ctf_link_out_string_cb_arg_t *arg = (ctf_link_out_string_cb_arg_t *) arg_;
316
317   fp->ctf_flags |= LCTF_DIRTY;
318   if (ctf_str_add_external (fp, arg->str, arg->offset) == NULL)
319     arg->err = ENOMEM;
320 }
321
322 /* Repeatedly call ADD_STRING to acquire strings from the external string table,
323    adding them to the atoms table for this CU and all subsidiary CUs.
324
325    If ctf_link() is also called, it must be called first if you want the new CTF
326    files ctf_link() can create to get their strings dedupped against the ELF
327    strtab properly.  */
328 int
329 ctf_link_add_strtab (ctf_file_t *fp, ctf_link_strtab_string_f *add_string,
330                      void *arg)
331 {
332   const char *str;
333   uint32_t offset;
334   int err = 0;
335
336   while ((str = add_string (&offset, arg)) != NULL)
337     {
338       ctf_link_out_string_cb_arg_t iter_arg = { str, offset, 0 };
339
340       fp->ctf_flags |= LCTF_DIRTY;
341       if (ctf_str_add_external (fp, str, offset) == NULL)
342         err = ENOMEM;
343
344       ctf_dynhash_iter (fp->ctf_link_outputs, ctf_link_intern_extern_string,
345                         &iter_arg);
346       if (iter_arg.err)
347         err = iter_arg.err;
348     }
349
350   return -err;
351 }
352
353 /* Not yet implemented.  */
354 int
355 ctf_link_shuffle_syms (ctf_file_t *fp _libctf_unused_,
356                        ctf_link_iter_symbol_f *add_sym _libctf_unused_,
357                        void *arg _libctf_unused_)
358 {
359   return 0;
360 }
361
362 typedef struct ctf_name_list_accum_cb_arg
363 {
364   char **names;
365   ctf_file_t *fp;
366   ctf_file_t **files;
367   size_t i;
368 } ctf_name_list_accum_cb_arg_t;
369
370 /* Accumulate the names and a count of the names in the link output hash,
371    and run ctf_update() on them to generate them.  */
372 static void
373 ctf_accumulate_archive_names (void *key, void *value, void *arg_)
374 {
375   const char *name = (const char *) key;
376   ctf_file_t *fp = (ctf_file_t *) value;
377   char **names;
378   ctf_file_t **files;
379   ctf_name_list_accum_cb_arg_t *arg = (ctf_name_list_accum_cb_arg_t *) arg_;
380   int err;
381
382   if ((err = ctf_update (fp)) < 0)
383     {
384       ctf_set_errno (arg->fp, ctf_errno (fp));
385       return;
386     }
387
388   if ((names = realloc (arg->names, sizeof (char *) * ++(arg->i))) == NULL)
389     {
390       (arg->i)--;
391       ctf_set_errno (arg->fp, ENOMEM);
392       return;
393     }
394
395   if ((files = realloc (arg->files, sizeof (ctf_file_t *) * arg->i)) == NULL)
396     {
397       (arg->i)--;
398       ctf_set_errno (arg->fp, ENOMEM);
399       return;
400     }
401   arg->names = names;
402   arg->names[(arg->i) - 1] = (char *) name;
403   arg->files = files;
404   arg->files[(arg->i) - 1] = fp;
405 }
406
407 /* Write out a CTF archive (if there are per-CU CTF files) or a CTF file
408    (otherwise) into a new dynamically-allocated string, and return it.
409    Members with sizes above THRESHOLD are compressed.  */
410 unsigned char *
411 ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold)
412 {
413   ctf_name_list_accum_cb_arg_t arg;
414   char **names;
415   ctf_file_t **files;
416   FILE *f = NULL;
417   int err;
418   long fsize;
419   const char *errloc;
420   unsigned char *buf = NULL;
421
422   memset (&arg, 0, sizeof (ctf_name_list_accum_cb_arg_t));
423   arg.fp = fp;
424
425   if (ctf_update (fp) < 0)
426     {
427       errloc = "CTF file construction";
428       goto err;
429     }
430
431   if (fp->ctf_link_outputs)
432     {
433       ctf_dynhash_iter (fp->ctf_link_outputs, ctf_accumulate_archive_names, &arg);
434       if (ctf_errno (fp) < 0)
435         {
436           errloc = "hash creation";
437           goto err;
438         }
439     }
440
441   /* No extra outputs? Just write a simple ctf_file_t.  */
442   if (arg.i == 0)
443     return ctf_write_mem (fp, size, threshold);
444
445   /* Writing an archive.  Stick ourselves (the shared repository, parent of all
446      other archives) on the front of it with the default name.  */
447   if ((names = realloc (arg.names, sizeof (char *) * (arg.i + 1))) == NULL)
448     {
449       errloc = "name reallocation";
450       goto err_no;
451     }
452   arg.names = names;
453   memmove (&(arg.names[1]), arg.names, sizeof (char *) * (arg.i));
454   arg.names[0] = (char *) _CTF_SECTION;
455
456   if ((files = realloc (arg.files,
457                         sizeof (struct ctf_file *) * (arg.i + 1))) == NULL)
458     {
459       errloc = "ctf_file reallocation";
460       goto err_no;
461     }
462   arg.files = files;
463   memmove (&(arg.files[1]), arg.files, sizeof (ctf_file_t *) * (arg.i));
464   arg.files[0] = fp;
465
466   if ((f = tmpfile ()) == NULL)
467     {
468       errloc = "tempfile creation";
469       goto err_no;
470     }
471
472   if ((err = ctf_arc_write_fd (fileno (f), arg.files, arg.i + 1,
473                                (const char **) arg.names,
474                                threshold)) < 0)
475     {
476       errloc = "archive writing";
477       ctf_set_errno (fp, err);
478       goto err;
479     }
480
481   if (fseek (f, 0, SEEK_END) < 0)
482     {
483       errloc = "seeking to end";
484       goto err_no;
485     }
486
487   if ((fsize = ftell (f)) < 0)
488     {
489       errloc = "filesize determination";
490       goto err_no;
491     }
492
493   if (fseek (f, 0, SEEK_SET) < 0)
494     {
495       errloc = "filepos resetting";
496       goto err_no;
497     }
498
499   if ((buf = malloc (fsize)) == NULL)
500     {
501       errloc = "CTF archive buffer allocation";
502       goto err_no;
503     }
504
505   while (!feof (f) && fread (buf, fsize, 1, f) == 0)
506     if (ferror (f))
507       {
508         errloc = "reading archive from temporary file";
509         goto err_no;
510       }
511
512   *size = fsize;
513   free (arg.names);
514   free (arg.files);
515   return buf;
516
517  err_no:
518   ctf_set_errno (fp, errno);
519  err:
520   free (buf);
521   if (f)
522     fclose (f);
523   free (arg.names);
524   free (arg.files);
525   ctf_dprintf ("Cannot write archive in link: %s failure: %s\n", errloc,
526                ctf_errmsg (ctf_errno (fp)));
527   return NULL;
528 }
This page took 0.05381 seconds and 4 git commands to generate.