GNU Binutils with patches for OS216
修订版 | 2091d7d550bf2c718ca1b4d613f81290868ed4c3 (tree) |
---|---|
时间 | 2019-09-23 22:12:54 |
作者 | Nick Alcock <nick.alcock@orac...> |
Commiter | Nick Alcock |
libctf: add CU-mapping machinery
Once the deduplicator is capable of actually detecting conflicting types
with the same name (i.e., not yet) we will place such conflicting types,
and types that depend on them, into CTF dictionaries that are the child
of the main dictionary we usually emit: currently, this will lead to the
.ctf section becoming a CTF archive rather than a single dictionary,
with the default-named archive member (_CTF_SECTION, or NULL) being the
main shared dictionary with most of the types in it.
By default, the sections are named after the compilation unit they come
from (complete path and all), with the cuname field in the CTF header
providing further evidence of the name without requiring the caller to
engage in tiresome parsing. But some callers may not wish the mapping
from input CU to output sub-dictionary to be purely CU-based.
The machinery here allows this to be freely changed, in two ways:
This is used by the kernel's ctfarchive machinery (not yet upstream) to
encode CTF under member names like {module name}.ctf rather than
.ctf.CU, but it is anticipated that other large projects may wish to
have their own storage for CTF outside of .ctf sections and may wish to
have new naming schemes that suit their special-purpose consumers.
New in v3.
v4: check for strdup failure.
include/
* ctf-api.h (ctf_link_add_cu_mapping): New.
(ctf_link_memb_name_changer_f): New.
(ctf_link_set_memb_name_changer): New.
libctf/
* ctf-impl.h (ctf_file_t) <ctf_link_cu_mappping>: New.
<ctf_link_memb_name_changer>: Likewise.
<ctf_link_memb_name_changer_arg>: Likewise.
* ctf-create.c (ctf_update): Update accordingly.
* ctf-open.c (ctf_file_close): Likewise.
* ctf-link.c (ctf_create_per_cu): Apply the cu mapping.
(ctf_link_add_cu_mapping): New.
(ctf_link_set_memb_name_changer): Likewise.
(ctf_name_list_accum_cb_arg_t) <dynames>: New, storage for names
allocated by the caller's ctf_link_memb_name_changer.
<ndynames>: Likewise.
(ctf_accumulate_archive_names): Call the ctf_link_memb_name_changer.
(ctf_link_write): Likewise (for _CTF_SECTION only): also call
@@ -1,3 +1,9 @@ | ||
1 | +2019-07-30 Nick Alcock <nick.alcock@oracle.com> | |
2 | + | |
3 | + * ctf-api.h (ctf_link_add_cu_mapping): New. | |
4 | + (ctf_link_memb_name_changer_f): New. | |
5 | + (ctf_link_set_memb_name_changer): New. | |
6 | + | |
1 | 7 | 2019-07-13 Nick Alcock <nick.alcock@oracle.com> |
2 | 8 | |
3 | 9 | * ctf-api.h (ECTF_INTERNAL): New. |
@@ -421,6 +421,16 @@ extern int ctf_link_shuffle_syms (ctf_file_t *, ctf_link_iter_symbol_f *, | ||
421 | 421 | extern unsigned char *ctf_link_write (ctf_file_t *, size_t *size, |
422 | 422 | size_t threshold); |
423 | 423 | |
424 | +/* Specialist linker functions. These functions are not used by ld, but can be | |
425 | + used by other prgorams making use of the linker machinery for other purposes | |
426 | + to customize its output. */ | |
427 | +extern int ctf_link_add_cu_mapping (ctf_file_t *, const char *from, | |
428 | + const char *to); | |
429 | +typedef char *ctf_link_memb_name_changer_f (ctf_file_t *, | |
430 | + const char *, void *); | |
431 | +extern void ctf_link_set_memb_name_changer | |
432 | + (ctf_file_t *, ctf_link_memb_name_changer_f *, void *); | |
433 | + | |
424 | 434 | extern void ctf_setdebug (int debug); |
425 | 435 | extern int ctf_getdebug (void); |
426 | 436 |
@@ -1,3 +1,21 @@ | ||
1 | +2019-07-30 Nick Alcock <nick.alcock@oracle.com> | |
2 | + | |
3 | + * ctf-impl.h (ctf_file_t) <ctf_link_cu_mappping>: New. | |
4 | + <ctf_link_memb_name_changer>: Likewise. | |
5 | + <ctf_link_memb_name_changer_arg>: Likewise. | |
6 | + * ctf-create.c (ctf_update): Update accordingly. | |
7 | + * ctf-open.c (ctf_file_close): Likewise. | |
8 | + * ctf-link.c (ctf_create_per_cu): Apply the cu mapping. | |
9 | + (ctf_link_add_cu_mapping): New. | |
10 | + (ctf_link_set_memb_name_changer): Likewise. | |
11 | + (ctf_change_parent_name): New. | |
12 | + (ctf_name_list_accum_cb_arg_t) <dynames>: New, storage for names | |
13 | + allocated by the caller's ctf_link_memb_name_changer. | |
14 | + <ndynames>: Likewise. | |
15 | + (ctf_accumulate_archive_names): Call the ctf_link_memb_name_changer. | |
16 | + (ctf_link_write): Likewise (for _CTF_SECTION only): also call | |
17 | + ctf_change_parent_name. Free any resulting names. | |
18 | + | |
1 | 19 | 2019-07-13 Nick Alcock <nick.alcock@oracle.com> |
2 | 20 | |
3 | 21 | * ctf-link.c (ctf_create_per_cu): New, refactored out of... |
@@ -473,7 +473,10 @@ ctf_update (ctf_file_t *fp) | ||
473 | 473 | nfp->ctf_link_inputs = fp->ctf_link_inputs; |
474 | 474 | nfp->ctf_link_outputs = fp->ctf_link_outputs; |
475 | 475 | nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab; |
476 | + nfp->ctf_link_cu_mapping = fp->ctf_link_cu_mapping; | |
476 | 477 | nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping; |
478 | + nfp->ctf_link_memb_name_changer = fp->ctf_link_memb_name_changer; | |
479 | + nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg; | |
477 | 480 | |
478 | 481 | nfp->ctf_snapshot_lu = fp->ctf_snapshots; |
479 | 482 |
@@ -486,6 +489,7 @@ ctf_update (ctf_file_t *fp) | ||
486 | 489 | fp->ctf_link_inputs = NULL; |
487 | 490 | fp->ctf_link_outputs = NULL; |
488 | 491 | fp->ctf_syn_ext_strtab = NULL; |
492 | + fp->ctf_link_cu_mapping = NULL; | |
489 | 493 | fp->ctf_link_type_mapping = NULL; |
490 | 494 | |
491 | 495 | fp->ctf_dvhash = NULL; |
@@ -281,6 +281,10 @@ struct ctf_file | ||
281 | 281 | ctf_dynhash_t *ctf_link_inputs; /* Inputs to this link. */ |
282 | 282 | ctf_dynhash_t *ctf_link_outputs; /* Additional outputs from this link. */ |
283 | 283 | ctf_dynhash_t *ctf_link_type_mapping; /* Map input types to output types. */ |
284 | + ctf_dynhash_t *ctf_link_cu_mapping; /* Map CU names to CTF dict names. */ | |
285 | + /* Allow the caller to Change the name of link archive members. */ | |
286 | + ctf_link_memb_name_changer_f *ctf_link_memb_name_changer; | |
287 | + void *ctf_link_memb_name_changer_arg; /* Argument for it. */ | |
284 | 288 | char *ctf_tmp_typeslice; /* Storage for slicing up type names. */ |
285 | 289 | size_t ctf_tmp_typeslicelen; /* Size of the typeslice. */ |
286 | 290 | void *ctf_specific; /* Data for ctf_get/setspecific(). */ |
@@ -182,9 +182,26 @@ static ctf_file_t * | ||
182 | 182 | ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname) |
183 | 183 | { |
184 | 184 | ctf_file_t *cu_fp; |
185 | + const char *ctf_name = NULL; | |
185 | 186 | char *dynname = NULL; |
186 | 187 | |
187 | - if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, filename)) == NULL) | |
188 | + /* First, check the mapping table and translate the per-CU name we use | |
189 | + accordingly. We check both the input filename and the CU name. Only if | |
190 | + neither are set do we fall back to the input filename as the per-CU | |
191 | + dictionary name. We prefer the filename because this is easier for likely | |
192 | + callers to determine. */ | |
193 | + | |
194 | + if (fp->ctf_link_cu_mapping) | |
195 | + { | |
196 | + if (((ctf_name = ctf_dynhash_lookup (fp->ctf_link_cu_mapping, filename)) == NULL) && | |
197 | + ((ctf_name = ctf_dynhash_lookup (fp->ctf_link_cu_mapping, cuname)) == NULL)) | |
198 | + ctf_name = filename; | |
199 | + } | |
200 | + | |
201 | + if (ctf_name == NULL) | |
202 | + ctf_name = filename; | |
203 | + | |
204 | + if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, ctf_name)) == NULL) | |
188 | 205 | { |
189 | 206 | int err; |
190 | 207 |
@@ -197,7 +214,7 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname) | ||
197 | 214 | return NULL; |
198 | 215 | } |
199 | 216 | |
200 | - if ((dynname = strdup (filename)) == NULL) | |
217 | + if ((dynname = strdup (ctf_name)) == NULL) | |
201 | 218 | goto oom; |
202 | 219 | if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, cu_fp) < 0) |
203 | 220 | goto oom; |
@@ -215,6 +232,79 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname) | ||
215 | 232 | return NULL; |
216 | 233 | } |
217 | 234 | |
235 | +/* Add a mapping directing that the CU named FROM should have its | |
236 | + conflicting/non-duplicate types (depending on link mode) go into a container | |
237 | + named TO. Many FROMs can share a TO: in this case, the effect on conflicting | |
238 | + types is not yet defined (but in time an auto-renaming algorithm will be | |
239 | + added: ugly, but there is really no right thing one can do in this | |
240 | + situation). | |
241 | + | |
242 | + We forcibly add a container named TO in every case, even though it may well | |
243 | + wind up empty, because clients that use this facility usually expect to find | |
244 | + every TO container present, even if empty, and malfunction otherwise. */ | |
245 | + | |
246 | +int | |
247 | +ctf_link_add_cu_mapping (ctf_file_t *fp, const char *from, const char *to) | |
248 | +{ | |
249 | + int err; | |
250 | + char *f, *t; | |
251 | + | |
252 | + if (fp->ctf_link_cu_mapping == NULL) | |
253 | + fp->ctf_link_cu_mapping = ctf_dynhash_create (ctf_hash_string, | |
254 | + ctf_hash_eq_string, free, | |
255 | + free); | |
256 | + if (fp->ctf_link_cu_mapping == NULL) | |
257 | + return ctf_set_errno (fp, ENOMEM); | |
258 | + | |
259 | + if (fp->ctf_link_outputs == NULL) | |
260 | + fp->ctf_link_outputs = ctf_dynhash_create (ctf_hash_string, | |
261 | + ctf_hash_eq_string, free, | |
262 | + ctf_file_close_thunk); | |
263 | + | |
264 | + if (fp->ctf_link_outputs == NULL) | |
265 | + return ctf_set_errno (fp, ENOMEM); | |
266 | + | |
267 | + f = strdup (from); | |
268 | + t = strdup (to); | |
269 | + if (!f || !t) | |
270 | + goto oom; | |
271 | + | |
272 | + if (ctf_create_per_cu (fp, t, t) == NULL) | |
273 | + goto oom_noerrno; /* Errno is set for us. */ | |
274 | + | |
275 | + err = ctf_dynhash_insert (fp->ctf_link_cu_mapping, f, t); | |
276 | + if (err) | |
277 | + { | |
278 | + ctf_set_errno (fp, err); | |
279 | + goto oom_noerrno; | |
280 | + } | |
281 | + | |
282 | + return 0; | |
283 | + | |
284 | + oom: | |
285 | + ctf_set_errno (fp, errno); | |
286 | + oom_noerrno: | |
287 | + free (f); | |
288 | + free (t); | |
289 | + return -1; | |
290 | +} | |
291 | + | |
292 | +/* Set a function which is called to transform the names of archive members. | |
293 | + This is useful for applying regular transformations to many names, where | |
294 | + ctf_link_add_cu_mapping applies arbitrarily irregular changes to single | |
295 | + names. The member name changer is applied at ctf_link_write time, so it | |
296 | + cannot conflate multiple CUs into one the way ctf_link_add_cu_mapping can. | |
297 | + The changer function accepts a name and should return a new | |
298 | + dynamically-allocated name, or NULL if the name should be left unchanged. */ | |
299 | +void | |
300 | +ctf_link_set_memb_name_changer (ctf_file_t *fp, | |
301 | + ctf_link_memb_name_changer_f *changer, | |
302 | + void *arg) | |
303 | +{ | |
304 | + fp->ctf_link_memb_name_changer = changer; | |
305 | + fp->ctf_link_memb_name_changer_arg = arg; | |
306 | +} | |
307 | + | |
218 | 308 | typedef struct ctf_link_in_member_cb_arg |
219 | 309 | { |
220 | 310 | ctf_file_t *out_fp; |
@@ -228,7 +318,6 @@ typedef struct ctf_link_in_member_cb_arg | ||
228 | 318 | int in_input_cu_file; |
229 | 319 | } ctf_link_in_member_cb_arg_t; |
230 | 320 | |
231 | - | |
232 | 321 | /* Link one type into the link. We rely on ctf_add_type() to detect |
233 | 322 | duplicates. This is not terribly reliable yet (unnmamed types will be |
234 | 323 | mindlessly duplicated), but will improve shortly. */ |
@@ -267,7 +356,7 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_) | ||
267 | 356 | ctf_set_errno (arg->out_fp, 0); |
268 | 357 | } |
269 | 358 | |
270 | - if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->arcname, | |
359 | + if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->file_name, | |
271 | 360 | arg->cu_name)) == NULL) |
272 | 361 | return -1; /* Errno is set for us. */ |
273 | 362 |
@@ -348,7 +437,7 @@ ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_) | ||
348 | 437 | type only present in the child. Try adding to the child, creating if need |
349 | 438 | be. */ |
350 | 439 | |
351 | - if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->arcname, | |
440 | + if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->file_name, | |
352 | 441 | arg->cu_name)) == NULL) |
353 | 442 | return -1; /* Errno is set for us. */ |
354 | 443 |
@@ -590,6 +679,8 @@ typedef struct ctf_name_list_accum_cb_arg | ||
590 | 679 | ctf_file_t *fp; |
591 | 680 | ctf_file_t **files; |
592 | 681 | size_t i; |
682 | + char **dynames; | |
683 | + size_t ndynames; | |
593 | 684 | } ctf_name_list_accum_cb_arg_t; |
594 | 685 | |
595 | 686 | /* Accumulate the names and a count of the names in the link output hash, |
@@ -623,12 +714,51 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_) | ||
623 | 714 | ctf_set_errno (arg->fp, ENOMEM); |
624 | 715 | return; |
625 | 716 | } |
717 | + | |
718 | + /* Allow the caller to get in and modify the name at the last minute. If the | |
719 | + caller *does* modify the name, we have to stash away the new name the | |
720 | + caller returned so we can free it later on. (The original name is the key | |
721 | + of the ctf_link_outputs hash and is freed by the dynhash machinery.) */ | |
722 | + | |
723 | + if (fp->ctf_link_memb_name_changer) | |
724 | + { | |
725 | + char **dynames; | |
726 | + char *dyname; | |
727 | + void *nc_arg = fp->ctf_link_memb_name_changer_arg; | |
728 | + | |
729 | + dyname = fp->ctf_link_memb_name_changer (fp, name, nc_arg); | |
730 | + | |
731 | + if (dyname != NULL) | |
732 | + { | |
733 | + if ((dynames = realloc (arg->dynames, | |
734 | + sizeof (char *) * ++(arg->ndynames))) == NULL) | |
735 | + { | |
736 | + (arg->ndynames)--; | |
737 | + ctf_set_errno (arg->fp, ENOMEM); | |
738 | + return; | |
739 | + } | |
740 | + arg->dynames = dynames; | |
741 | + name = (const char *) dyname; | |
742 | + } | |
743 | + } | |
744 | + | |
626 | 745 | arg->names = names; |
627 | 746 | arg->names[(arg->i) - 1] = (char *) name; |
628 | 747 | arg->files = files; |
629 | 748 | arg->files[(arg->i) - 1] = fp; |
630 | 749 | } |
631 | 750 | |
751 | +/* Change the name of the parent CTF section, if the name transformer has got to | |
752 | + it. */ | |
753 | +static void | |
754 | +ctf_change_parent_name (void *key _libctf_unused_, void *value, void *arg) | |
755 | +{ | |
756 | + ctf_file_t *fp = (ctf_file_t *) value; | |
757 | + const char *name = (const char *) arg; | |
758 | + | |
759 | + ctf_parent_name_set (fp, name); | |
760 | +} | |
761 | + | |
632 | 762 | /* Write out a CTF archive (if there are per-CU CTF files) or a CTF file |
633 | 763 | (otherwise) into a new dynamically-allocated string, and return it. |
634 | 764 | Members with sizes above THRESHOLD are compressed. */ |
@@ -637,6 +767,7 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold) | ||
637 | 767 | { |
638 | 768 | ctf_name_list_accum_cb_arg_t arg; |
639 | 769 | char **names; |
770 | + char *transformed_name = NULL; | |
640 | 771 | ctf_file_t **files; |
641 | 772 | FILE *f = NULL; |
642 | 773 | int err; |
@@ -676,7 +807,22 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold) | ||
676 | 807 | } |
677 | 808 | arg.names = names; |
678 | 809 | memmove (&(arg.names[1]), arg.names, sizeof (char *) * (arg.i)); |
810 | + | |
679 | 811 | arg.names[0] = (char *) _CTF_SECTION; |
812 | + if (fp->ctf_link_memb_name_changer) | |
813 | + { | |
814 | + void *nc_arg = fp->ctf_link_memb_name_changer_arg; | |
815 | + | |
816 | + transformed_name = fp->ctf_link_memb_name_changer (fp, _CTF_SECTION, | |
817 | + nc_arg); | |
818 | + | |
819 | + if (transformed_name != NULL) | |
820 | + { | |
821 | + arg.names[0] = transformed_name; | |
822 | + ctf_dynhash_iter (fp->ctf_link_outputs, ctf_change_parent_name, | |
823 | + transformed_name); | |
824 | + } | |
825 | + } | |
680 | 826 | |
681 | 827 | if ((files = realloc (arg.files, |
682 | 828 | sizeof (struct ctf_file *) * (arg.i + 1))) == NULL) |
@@ -737,6 +883,14 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold) | ||
737 | 883 | *size = fsize; |
738 | 884 | free (arg.names); |
739 | 885 | free (arg.files); |
886 | + free (transformed_name); | |
887 | + if (arg.ndynames) | |
888 | + { | |
889 | + size_t i; | |
890 | + for (i = 0; i < arg.ndynames; i++) | |
891 | + free (arg.dynames[i]); | |
892 | + free (arg.dynames); | |
893 | + } | |
740 | 894 | return buf; |
741 | 895 | |
742 | 896 | err_no: |
@@ -747,6 +901,14 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold) | ||
747 | 901 | fclose (f); |
748 | 902 | free (arg.names); |
749 | 903 | free (arg.files); |
904 | + free (transformed_name); | |
905 | + if (arg.ndynames) | |
906 | + { | |
907 | + size_t i; | |
908 | + for (i = 0; i < arg.ndynames; i++) | |
909 | + free (arg.dynames[i]); | |
910 | + free (arg.dynames); | |
911 | + } | |
750 | 912 | ctf_dprintf ("Cannot write archive in link: %s failure: %s\n", errloc, |
751 | 913 | ctf_errmsg (ctf_errno (fp))); |
752 | 914 | return NULL; |
@@ -1629,6 +1629,7 @@ ctf_file_close (ctf_file_t *fp) | ||
1629 | 1629 | ctf_dynhash_destroy (fp->ctf_link_inputs); |
1630 | 1630 | ctf_dynhash_destroy (fp->ctf_link_outputs); |
1631 | 1631 | ctf_dynhash_destroy (fp->ctf_link_type_mapping); |
1632 | + ctf_dynhash_destroy (fp->ctf_link_cu_mapping); | |
1632 | 1633 | |
1633 | 1634 | ctf_free (fp->ctf_sxlate); |
1634 | 1635 | ctf_free (fp->ctf_txlate); |