1 /* 2 * (C) Copyright David Gibson <dwg (at) au1.ibm.com>, IBM Corporation. 2005. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21 #include "dtc.h" 22 23 /* 24 * Tree building functions 25 */ 26 27 void add_label(struct label **labels, char *label) 28 { 29 struct label *new; 30 31 /* Make sure the label isn't already there */ 32 for_each_label_withdel(*labels, new) 33 if (streq(new->label, label)) { 34 new->deleted = 0; 35 return; 36 } 37 38 new = xmalloc(sizeof(*new)); 39 memset(new, 0, sizeof(*new)); 40 new->label = label; 41 new->next = *labels; 42 *labels = new; 43 } 44 45 void delete_labels(struct label **labels) 46 { 47 struct label *label; 48 49 for_each_label(*labels, label) 50 label->deleted = 1; 51 } 52 53 struct property *build_property(char *name, struct data val) 54 { 55 struct property *new = xmalloc(sizeof(*new)); 56 57 memset(new, 0, sizeof(*new)); 58 59 new->name = name; 60 new->val = val; 61 62 return new; 63 } 64 65 struct property *build_property_delete(char *name) 66 { 67 struct property *new = xmalloc(sizeof(*new)); 68 69 memset(new, 0, sizeof(*new)); 70 71 new->name = name; 72 new->deleted = 1; 73 74 return new; 75 } 76 77 struct property *chain_property(struct property *first, struct property *list) 78 { 79 assert(first->next == NULL); 80 81 first->next = list; 82 return first; 83 } 84 85 struct property *reverse_properties(struct property *first) 86 { 87 struct property *p = first; 88 struct property *head = NULL; 89 struct property *next; 90 91 while (p) { 92 next = p->next; 93 p->next = head; 94 head = p; 95 p = next; 96 } 97 return head; 98 } 99 100 struct node *build_node(struct property *proplist, struct node *children) 101 { 102 struct node *new = xmalloc(sizeof(*new)); 103 struct node *child; 104 105 memset(new, 0, sizeof(*new)); 106 107 new->proplist = reverse_properties(proplist); 108 new->children = children; 109 110 for_each_child(new, child) { 111 child->parent = new; 112 } 113 114 return new; 115 } 116 117 struct node *build_node_delete(void) 118 { 119 struct node *new = xmalloc(sizeof(*new)); 120 121 memset(new, 0, sizeof(*new)); 122 123 new->deleted = 1; 124 125 return new; 126 } 127 128 struct node *name_node(struct node *node, char *name) 129 { 130 assert(node->name == NULL); 131 132 node->name = name; 133 134 return node; 135 } 136 137 struct node *merge_nodes(struct node *old_node, struct node *new_node) 138 { 139 struct property *new_prop, *old_prop; 140 struct node *new_child, *old_child; 141 struct label *l; 142 143 old_node->deleted = 0; 144 145 /* Add new node labels to old node */ 146 for_each_label_withdel(new_node->labels, l) 147 add_label(&old_node->labels, l->label); 148 149 /* Move properties from the new node to the old node. If there 150 * is a collision, replace the old value with the new */ 151 while (new_node->proplist) { 152 /* Pop the property off the list */ 153 new_prop = new_node->proplist; 154 new_node->proplist = new_prop->next; 155 new_prop->next = NULL; 156 157 if (new_prop->deleted) { 158 delete_property_by_name(old_node, new_prop->name); 159 free(new_prop); 160 continue; 161 } 162 163 /* Look for a collision, set new value if there is */ 164 for_each_property_withdel(old_node, old_prop) { 165 if (streq(old_prop->name, new_prop->name)) { 166 /* Add new labels to old property */ 167 for_each_label_withdel(new_prop->labels, l) 168 add_label(&old_prop->labels, l->label); 169 170 old_prop->val = new_prop->val; 171 old_prop->deleted = 0; 172 free(new_prop); 173 new_prop = NULL; 174 break; 175 } 176 } 177 178 /* if no collision occurred, add property to the old node. */ 179 if (new_prop) 180 add_property(old_node, new_prop); 181 } 182 183 /* Move the override child nodes into the primary node. If 184 * there is a collision, then merge the nodes. */ 185 while (new_node->children) { 186 /* Pop the child node off the list */ 187 new_child = new_node->children; 188 new_node->children = new_child->next_sibling; 189 new_child->parent = NULL; 190 new_child->next_sibling = NULL; 191 192 if (new_child->deleted) { 193 delete_node_by_name(old_node, new_child->name); 194 free(new_child); 195 continue; 196 } 197 198 /* Search for a collision. Merge if there is */ 199 for_each_child_withdel(old_node, old_child) { 200 if (streq(old_child->name, new_child->name)) { 201 merge_nodes(old_child, new_child); 202 new_child = NULL; 203 break; 204 } 205 } 206 207 /* if no collision occurred, add child to the old node. */ 208 if (new_child) 209 add_child(old_node, new_child); 210 } 211 212 /* The new node contents are now merged into the old node. Free 213 * the new node. */ 214 free(new_node); 215 216 return old_node; 217 } 218 219 void add_orphan_node(struct node *dt, struct node *new_node, char *ref) 220 { 221 static unsigned int next_orphan_fragment = 0; 222 struct node *node; 223 struct property *p; 224 struct data d = empty_data; 225 char *name; 226 227 d = data_add_marker(d, REF_PHANDLE, ref); 228 d = data_append_integer(d, 0xffffffff, 32); 229 230 p = build_property("target", d); 231 232 xasprintf(&name, "fragment@%u", 233 next_orphan_fragment++); 234 name_node(new_node, "__overlay__"); 235 node = build_node(p, new_node); 236 name_node(node, name); 237 238 add_child(dt, node); 239 } 240 241 struct node *chain_node(struct node *first, struct node *list) 242 { 243 assert(first->next_sibling == NULL); 244 245 first->next_sibling = list; 246 return first; 247 } 248 249 void add_property(struct node *node, struct property *prop) 250 { 251 struct property **p; 252 253 prop->next = NULL; 254 255 p = &node->proplist; 256 while (*p) 257 p = &((*p)->next); 258 259 *p = prop; 260 } 261 262 void delete_property_by_name(struct node *node, char *name) 263 { 264 struct property *prop = node->proplist; 265 266 while (prop) { 267 if (streq(prop->name, name)) { 268 delete_property(prop); 269 return; 270 } 271 prop = prop->next; 272 } 273 } 274 275 void delete_property(struct property *prop) 276 { 277 prop->deleted = 1; 278 delete_labels(&prop->labels); 279 } 280 281 void add_child(struct node *parent, struct node *child) 282 { 283 struct node **p; 284 285 child->next_sibling = NULL; 286 child->parent = parent; 287 288 p = &parent->children; 289 while (*p) 290 p = &((*p)->next_sibling); 291 292 *p = child; 293 } 294 295 void delete_node_by_name(struct node *parent, char *name) 296 { 297 struct node *node = parent->children; 298 299 while (node) { 300 if (streq(node->name, name)) { 301 delete_node(node); 302 return; 303 } 304 node = node->next_sibling; 305 } 306 } 307 308 void delete_node(struct node *node) 309 { 310 struct property *prop; 311 struct node *child; 312 313 node->deleted = 1; 314 for_each_child(node, child) 315 delete_node(child); 316 for_each_property(node, prop) 317 delete_property(prop); 318 delete_labels(&node->labels); 319 } 320 321 void append_to_property(struct node *node, 322 char *name, const void *data, int len) 323 { 324 struct data d; 325 struct property *p; 326 327 p = get_property(node, name); 328 if (p) { 329 d = data_append_data(p->val, data, len); 330 p->val = d; 331 } else { 332 d = data_append_data(empty_data, data, len); 333 p = build_property(name, d); 334 add_property(node, p); 335 } 336 } 337 338 struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) 339 { 340 struct reserve_info *new = xmalloc(sizeof(*new)); 341 342 memset(new, 0, sizeof(*new)); 343 344 new->address = address; 345 new->size = size; 346 347 return new; 348 } 349 350 struct reserve_info *chain_reserve_entry(struct reserve_info *first, 351 struct reserve_info *list) 352 { 353 assert(first->next == NULL); 354 355 first->next = list; 356 return first; 357 } 358 359 struct reserve_info *add_reserve_entry(struct reserve_info *list, 360 struct reserve_info *new) 361 { 362 struct reserve_info *last; 363 364 new->next = NULL; 365 366 if (! list) 367 return new; 368 369 for (last = list; last->next; last = last->next) 370 ; 371 372 last->next = new; 373 374 return list; 375 } 376 377 struct dt_info *build_dt_info(unsigned int dtsflags, 378 struct reserve_info *reservelist, 379 struct node *tree, uint32_t boot_cpuid_phys) 380 { 381 struct dt_info *dti; 382 383 dti = xmalloc(sizeof(*dti)); 384 dti->dtsflags = dtsflags; 385 dti->reservelist = reservelist; 386 dti->dt = tree; 387 dti->boot_cpuid_phys = boot_cpuid_phys; 388 389 return dti; 390 } 391 392 /* 393 * Tree accessor functions 394 */ 395 396 const char *get_unitname(struct node *node) 397 { 398 if (node->name[node->basenamelen] == '\0') 399 return ""; 400 else 401 return node->name + node->basenamelen + 1; 402 } 403 404 struct property *get_property(struct node *node, const char *propname) 405 { 406 struct property *prop; 407 408 for_each_property(node, prop) 409 if (streq(prop->name, propname)) 410 return prop; 411 412 return NULL; 413 } 414 415 cell_t propval_cell(struct property *prop) 416 { 417 assert(prop->val.len == sizeof(cell_t)); 418 return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); 419 } 420 421 struct property *get_property_by_label(struct node *tree, const char *label, 422 struct node **node) 423 { 424 struct property *prop; 425 struct node *c; 426 427 *node = tree; 428 429 for_each_property(tree, prop) { 430 struct label *l; 431 432 for_each_label(prop->labels, l) 433 if (streq(l->label, label)) 434 return prop; 435 } 436 437 for_each_child(tree, c) { 438 prop = get_property_by_label(c, label, node); 439 if (prop) 440 return prop; 441 } 442 443 *node = NULL; 444 return NULL; 445 } 446 447 struct marker *get_marker_label(struct node *tree, const char *label, 448 struct node **node, struct property **prop) 449 { 450 struct marker *m; 451 struct property *p; 452 struct node *c; 453 454 *node = tree; 455 456 for_each_property(tree, p) { 457 *prop = p; 458 m = p->val.markers; 459 for_each_marker_of_type(m, LABEL) 460 if (streq(m->ref, label)) 461 return m; 462 } 463 464 for_each_child(tree, c) { 465 m = get_marker_label(c, label, node, prop); 466 if (m) 467 return m; 468 } 469 470 *prop = NULL; 471 *node = NULL; 472 return NULL; 473 } 474 475 struct node *get_subnode(struct node *node, const char *nodename) 476 { 477 struct node *child; 478 479 for_each_child(node, child) 480 if (streq(child->name, nodename)) 481 return child; 482 483 return NULL; 484 } 485 486 struct node *get_node_by_path(struct node *tree, const char *path) 487 { 488 const char *p; 489 struct node *child; 490 491 if (!path || ! (*path)) { 492 if (tree->deleted) 493 return NULL; 494 return tree; 495 } 496 497 while (path[0] == '/') 498 path++; 499 500 p = strchr(path, '/'); 501 502 for_each_child(tree, child) { 503 if (p && strneq(path, child->name, p-path)) 504 return get_node_by_path(child, p+1); 505 else if (!p && streq(path, child->name)) 506 return child; 507 } 508 509 return NULL; 510 } 511 512 struct node *get_node_by_label(struct node *tree, const char *label) 513 { 514 struct node *child, *node; 515 struct label *l; 516 517 assert(label && (strlen(label) > 0)); 518 519 for_each_label(tree->labels, l) 520 if (streq(l->label, label)) 521 return tree; 522 523 for_each_child(tree, child) { 524 node = get_node_by_label(child, label); 525 if (node) 526 return node; 527 } 528 529 return NULL; 530 } 531 532 struct node *get_node_by_phandle(struct node *tree, cell_t phandle) 533 { 534 struct node *child, *node; 535 536 assert((phandle != 0) && (phandle != -1)); 537 538 if (tree->phandle == phandle) { 539 if (tree->deleted) 540 return NULL; 541 return tree; 542 } 543 544 for_each_child(tree, child) { 545 node = get_node_by_phandle(child, phandle); 546 if (node) 547 return node; 548 } 549 550 return NULL; 551 } 552 553 struct node *get_node_by_ref(struct node *tree, const char *ref) 554 { 555 if (streq(ref, "/")) 556 return tree; 557 else if (ref[0] == '/') 558 return get_node_by_path(tree, ref); 559 else 560 return get_node_by_label(tree, ref); 561 } 562 563 cell_t get_node_phandle(struct node *root, struct node *node) 564 { 565 static cell_t phandle = 1; /* FIXME: ick, static local */ 566 567 if ((node->phandle != 0) && (node->phandle != -1)) 568 return node->phandle; 569 570 while (get_node_by_phandle(root, phandle)) 571 phandle++; 572 573 node->phandle = phandle; 574 575 if (!get_property(node, "linux,phandle") 576 && (phandle_format & PHANDLE_LEGACY)) 577 add_property(node, 578 build_property("linux,phandle", 579 data_append_cell(empty_data, phandle))); 580 581 if (!get_property(node, "phandle") 582 && (phandle_format & PHANDLE_EPAPR)) 583 add_property(node, 584 build_property("phandle", 585 data_append_cell(empty_data, phandle))); 586 587 /* If the node *does* have a phandle property, we must 588 * be dealing with a self-referencing phandle, which will be 589 * fixed up momentarily in the caller */ 590 591 return node->phandle; 592 } 593 594 uint32_t guess_boot_cpuid(struct node *tree) 595 { 596 struct node *cpus, *bootcpu; 597 struct property *reg; 598 599 cpus = get_node_by_path(tree, "/cpus"); 600 if (!cpus) 601 return 0; 602 603 604 bootcpu = cpus->children; 605 if (!bootcpu) 606 return 0; 607 608 reg = get_property(bootcpu, "reg"); 609 if (!reg || (reg->val.len != sizeof(uint32_t))) 610 return 0; 611 612 /* FIXME: Sanity check node? */ 613 614 return propval_cell(reg); 615 } 616 617 static int cmp_reserve_info(const void *ax, const void *bx) 618 { 619 const struct reserve_info *a, *b; 620 621 a = *((const struct reserve_info * const *)ax); 622 b = *((const struct reserve_info * const *)bx); 623 624 if (a->address < b->address) 625 return -1; 626 else if (a->address > b->address) 627 return 1; 628 else if (a->size < b->size) 629 return -1; 630 else if (a->size > b->size) 631 return 1; 632 else 633 return 0; 634 } 635 636 static void sort_reserve_entries(struct dt_info *dti) 637 { 638 struct reserve_info *ri, **tbl; 639 int n = 0, i = 0; 640 641 for (ri = dti->reservelist; 642 ri; 643 ri = ri->next) 644 n++; 645 646 if (n == 0) 647 return; 648 649 tbl = xmalloc(n * sizeof(*tbl)); 650 651 for (ri = dti->reservelist; 652 ri; 653 ri = ri->next) 654 tbl[i++] = ri; 655 656 qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); 657 658 dti->reservelist = tbl[0]; 659 for (i = 0; i < (n-1); i++) 660 tbl[i]->next = tbl[i+1]; 661 tbl[n-1]->next = NULL; 662 663 free(tbl); 664 } 665 666 static int cmp_prop(const void *ax, const void *bx) 667 { 668 const struct property *a, *b; 669 670 a = *((const struct property * const *)ax); 671 b = *((const struct property * const *)bx); 672 673 return strcmp(a->name, b->name); 674 } 675 676 static void sort_properties(struct node *node) 677 { 678 int n = 0, i = 0; 679 struct property *prop, **tbl; 680 681 for_each_property_withdel(node, prop) 682 n++; 683 684 if (n == 0) 685 return; 686 687 tbl = xmalloc(n * sizeof(*tbl)); 688 689 for_each_property_withdel(node, prop) 690 tbl[i++] = prop; 691 692 qsort(tbl, n, sizeof(*tbl), cmp_prop); 693 694 node->proplist = tbl[0]; 695 for (i = 0; i < (n-1); i++) 696 tbl[i]->next = tbl[i+1]; 697 tbl[n-1]->next = NULL; 698 699 free(tbl); 700 } 701 702 static int cmp_subnode(const void *ax, const void *bx) 703 { 704 const struct node *a, *b; 705 706 a = *((const struct node * const *)ax); 707 b = *((const struct node * const *)bx); 708 709 return strcmp(a->name, b->name); 710 } 711 712 static void sort_subnodes(struct node *node) 713 { 714 int n = 0, i = 0; 715 struct node *subnode, **tbl; 716 717 for_each_child_withdel(node, subnode) 718 n++; 719 720 if (n == 0) 721 return; 722 723 tbl = xmalloc(n * sizeof(*tbl)); 724 725 for_each_child_withdel(node, subnode) 726 tbl[i++] = subnode; 727 728 qsort(tbl, n, sizeof(*tbl), cmp_subnode); 729 730 node->children = tbl[0]; 731 for (i = 0; i < (n-1); i++) 732 tbl[i]->next_sibling = tbl[i+1]; 733 tbl[n-1]->next_sibling = NULL; 734 735 free(tbl); 736 } 737 738 static void sort_node(struct node *node) 739 { 740 struct node *c; 741 742 sort_properties(node); 743 sort_subnodes(node); 744 for_each_child_withdel(node, c) 745 sort_node(c); 746 } 747 748 void sort_tree(struct dt_info *dti) 749 { 750 sort_reserve_entries(dti); 751 sort_node(dti->dt); 752 } 753 754 /* utility helper to avoid code duplication */ 755 static struct node *build_and_name_child_node(struct node *parent, char *name) 756 { 757 struct node *node; 758 759 node = build_node(NULL, NULL); 760 name_node(node, xstrdup(name)); 761 add_child(parent, node); 762 763 return node; 764 } 765 766 static struct node *build_root_node(struct node *dt, char *name) 767 { 768 struct node *an; 769 770 an = get_subnode(dt, name); 771 if (!an) 772 an = build_and_name_child_node(dt, name); 773 774 if (!an) 775 die("Could not build root node /%s\n", name); 776 777 return an; 778 } 779 780 static bool any_label_tree(struct dt_info *dti, struct node *node) 781 { 782 struct node *c; 783 784 if (node->labels) 785 return true; 786 787 for_each_child(node, c) 788 if (any_label_tree(dti, c)) 789 return true; 790 791 return false; 792 } 793 794 static void generate_label_tree_internal(struct dt_info *dti, 795 struct node *an, struct node *node, 796 bool allocph) 797 { 798 struct node *dt = dti->dt; 799 struct node *c; 800 struct property *p; 801 struct label *l; 802 803 /* if there are labels */ 804 if (node->labels) { 805 806 /* now add the label in the node */ 807 for_each_label(node->labels, l) { 808 809 /* check whether the label already exists */ 810 p = get_property(an, l->label); 811 if (p) { 812 fprintf(stderr, "WARNING: label %s already" 813 " exists in /%s", l->label, 814 an->name); 815 continue; 816 } 817 818 /* insert it */ 819 p = build_property(l->label, 820 data_copy_mem(node->fullpath, 821 strlen(node->fullpath) + 1)); 822 add_property(an, p); 823 } 824 825 /* force allocation of a phandle for this node */ 826 if (allocph) 827 (void)get_node_phandle(dt, node); 828 } 829 830 for_each_child(node, c) 831 generate_label_tree_internal(dti, an, c, allocph); 832 } 833 834 static bool any_fixup_tree(struct dt_info *dti, struct node *node) 835 { 836 struct node *c; 837 struct property *prop; 838 struct marker *m; 839 840 for_each_property(node, prop) { 841 m = prop->val.markers; 842 for_each_marker_of_type(m, REF_PHANDLE) { 843 if (!get_node_by_ref(dti->dt, m->ref)) 844 return true; 845 } 846 } 847 848 for_each_child(node, c) { 849 if (any_fixup_tree(dti, c)) 850 return true; 851 } 852 853 return false; 854 } 855 856 static void add_fixup_entry(struct dt_info *dti, struct node *fn, 857 struct node *node, struct property *prop, 858 struct marker *m) 859 { 860 char *entry; 861 862 /* m->ref can only be a REF_PHANDLE, but check anyway */ 863 assert(m->type == REF_PHANDLE); 864 865 /* there shouldn't be any ':' in the arguments */ 866 if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) 867 die("arguments should not contain ':'\n"); 868 869 xasprintf(&entry, "%s:%s:%u", 870 node->fullpath, prop->name, m->offset); 871 append_to_property(fn, m->ref, entry, strlen(entry) + 1); 872 873 free(entry); 874 } 875 876 static void generate_fixups_tree_internal(struct dt_info *dti, 877 struct node *fn, 878 struct node *node) 879 { 880 struct node *dt = dti->dt; 881 struct node *c; 882 struct property *prop; 883 struct marker *m; 884 struct node *refnode; 885 886 for_each_property(node, prop) { 887 m = prop->val.markers; 888 for_each_marker_of_type(m, REF_PHANDLE) { 889 refnode = get_node_by_ref(dt, m->ref); 890 if (!refnode) 891 add_fixup_entry(dti, fn, node, prop, m); 892 } 893 } 894 895 for_each_child(node, c) 896 generate_fixups_tree_internal(dti, fn, c); 897 } 898 899 static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) 900 { 901 struct node *c; 902 struct property *prop; 903 struct marker *m; 904 905 for_each_property(node, prop) { 906 m = prop->val.markers; 907 for_each_marker_of_type(m, REF_PHANDLE) { 908 if (get_node_by_ref(dti->dt, m->ref)) 909 return true; 910 } 911 } 912 913 for_each_child(node, c) { 914 if (any_local_fixup_tree(dti, c)) 915 return true; 916 } 917 918 return false; 919 } 920 921 static void add_local_fixup_entry(struct dt_info *dti, 922 struct node *lfn, struct node *node, 923 struct property *prop, struct marker *m, 924 struct node *refnode) 925 { 926 struct node *wn, *nwn; /* local fixup node, walk node, new */ 927 fdt32_t value_32; 928 char **compp; 929 int i, depth; 930 931 /* walk back retreiving depth */ 932 depth = 0; 933 for (wn = node; wn; wn = wn->parent) 934 depth++; 935 936 /* allocate name array */ 937 compp = xmalloc(sizeof(*compp) * depth); 938 939 /* store names in the array */ 940 for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) 941 compp[i] = wn->name; 942 943 /* walk the path components creating nodes if they don't exist */ 944 for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { 945 /* if no node exists, create it */ 946 nwn = get_subnode(wn, compp[i]); 947 if (!nwn) 948 nwn = build_and_name_child_node(wn, compp[i]); 949 } 950 951 free(compp); 952 953 value_32 = cpu_to_fdt32(m->offset); 954 append_to_property(wn, prop->name, &value_32, sizeof(value_32)); 955 } 956 957 static void generate_local_fixups_tree_internal(struct dt_info *dti, 958 struct node *lfn, 959 struct node *node) 960 { 961 struct node *dt = dti->dt; 962 struct node *c; 963 struct property *prop; 964 struct marker *m; 965 struct node *refnode; 966 967 for_each_property(node, prop) { 968 m = prop->val.markers; 969 for_each_marker_of_type(m, REF_PHANDLE) { 970 refnode = get_node_by_ref(dt, m->ref); 971 if (refnode) 972 add_local_fixup_entry(dti, lfn, node, prop, m, refnode); 973 } 974 } 975 976 for_each_child(node, c) 977 generate_local_fixups_tree_internal(dti, lfn, c); 978 } 979 980 void generate_label_tree(struct dt_info *dti, char *name, bool allocph) 981 { 982 if (!any_label_tree(dti, dti->dt)) 983 return; 984 generate_label_tree_internal(dti, build_root_node(dti->dt, name), 985 dti->dt, allocph); 986 } 987 988 void generate_fixups_tree(struct dt_info *dti, char *name) 989 { 990 if (!any_fixup_tree(dti, dti->dt)) 991 return; 992 generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), 993 dti->dt); 994 } 995 996 void generate_local_fixups_tree(struct dt_info *dti, char *name) 997 { 998 if (!any_local_fixup_tree(dti, dti->dt)) 999 return; 1000 generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), 1001 dti->dt); 1002 } 1003