2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 #include <libsa/vers_rsrc.h>
34 #include "vers_rsrc.h"
41 static void __dgraph_entry_free(dgraph_entry_t
* entry
);
44 /*******************************************************************************
46 *******************************************************************************/
47 char * strdup(const char * string
)
52 length
= strlen(string
);
53 dup
= (char *)malloc((1+length
) * sizeof(char));
63 /*******************************************************************************
65 *******************************************************************************/
66 dgraph_error_t
dgraph_init(dgraph_t
* dgraph
)
68 bzero(dgraph
, sizeof(dgraph_t
));
70 dgraph
->capacity
= (5); // pulled from a hat
72 /* Make sure list is big enough & graph has a good start size.
74 dgraph
->graph
= (dgraph_entry_t
**)malloc(
75 dgraph
->capacity
* sizeof(dgraph_entry_t
*));
85 /*******************************************************************************
87 *******************************************************************************/
88 dgraph_error_t
dgraph_init_with_arglist(
91 const char * dependency_delimiter
,
92 const char * kernel_dependency_delimiter
,
96 dgraph_error_t result
= dgraph_valid
;
98 int found_zero_load_address
= 0;
99 int found_nonzero_load_address
= 0;
100 dgraph_entry_t
* current_dependent
= NULL
;
101 char kernel_dependencies
= 0;
103 result
= dgraph_init(dgraph
);
104 if (result
!= dgraph_valid
) {
108 for (i
= 0; i
< argc
; i
++) {
109 vm_address_t load_address
= 0;
111 if (0 == strcmp(argv
[i
], dependency_delimiter
)) {
112 kernel_dependencies
= 0;
113 current_dependent
= NULL
;
115 } else if (0 == strcmp(argv
[i
], kernel_dependency_delimiter
)) {
116 kernel_dependencies
= 1;
117 current_dependent
= NULL
;
121 if (expect_addresses
) {
122 char * address
= rindex(argv
[i
], '@');
124 *address
++ = 0; // snip the address from the filename
125 load_address
= strtoul(address
, NULL
, 0);
129 if (!current_dependent
) {
130 current_dependent
= dgraph_add_dependent(dgraph
, argv
[i
],
131 /* expected kmod name */ NULL
, /* expected vers */ 0,
133 if (!current_dependent
) {
137 if (!dgraph_add_dependency(dgraph
, current_dependent
, argv
[i
],
138 /* expected kmod name */ NULL
, /* expected vers */ 0,
139 load_address
, kernel_dependencies
)) {
146 dgraph
->root
= dgraph_find_root(dgraph
);
147 dgraph_establish_load_order(dgraph
);
150 kload_log_error("dependency graph has no root" KNL
);
151 return dgraph_invalid
;
154 if (dgraph
->root
->is_kernel_component
&& !dgraph
->root
->is_symbol_set
) {
155 kload_log_error("dependency graph root is a kernel component" KNL
);
156 return dgraph_invalid
;
159 for (i
= 0; i
< dgraph
->length
; i
++) {
160 if (dgraph
->graph
[i
]->loaded_address
== 0) {
161 found_zero_load_address
= 1;
163 found_nonzero_load_address
= 1;
166 (found_zero_load_address
&& found_nonzero_load_address
)) {
169 "load addresses must be specified for all module files" KNL
);
170 return dgraph_invalid
;
176 #endif /* not KERNEL */
178 /*******************************************************************************
180 *******************************************************************************/
181 static void __dgraph_entry_free(dgraph_entry_t
* entry
)
187 if (entry
->expected_kmod_name
) {
188 free(entry
->expected_kmod_name
);
189 entry
->expected_kmod_name
= NULL
;
191 if (entry
->expected_kmod_vers
) {
192 free(entry
->expected_kmod_vers
);
193 entry
->expected_kmod_vers
= NULL
;
195 if (entry
->dependencies
) {
196 free(entry
->dependencies
);
197 entry
->dependencies
= NULL
;
199 if (entry
->symbols_malloc
) {
200 free((void *) entry
->symbols_malloc
);
201 entry
->symbols_malloc
= NULL
;
207 /*******************************************************************************
209 *******************************************************************************/
214 unsigned int entry_index
;
220 for (entry_index
= 0; entry_index
< dgraph
->length
; entry_index
++) {
221 dgraph_entry_t
* current
= dgraph
->graph
[entry_index
];
222 __dgraph_entry_free(current
);
227 dgraph
->graph
= NULL
;
230 if (dgraph
->load_order
) {
231 free(dgraph
->load_order
);
232 dgraph
->load_order
= NULL
;
235 if (free_graph
&& dgraph
) {
243 /*******************************************************************************
245 *******************************************************************************/
246 dgraph_entry_t
* dgraph_find_root(dgraph_t
* dgraph
) {
247 dgraph_entry_t
* root
= NULL
;
248 dgraph_entry_t
* candidate
= NULL
;
249 unsigned int candidate_index
;
250 unsigned int scan_index
;
251 unsigned int dep_index
;
254 /* Scan each entry in the graph for one that isn't in any other entry's
257 for (candidate_index
= 0; candidate_index
< dgraph
->length
;
260 candidate
= dgraph
->graph
[candidate_index
];
262 for (scan_index
= 0; scan_index
< dgraph
->length
; scan_index
++) {
264 dgraph_entry_t
* scan_entry
= dgraph
->graph
[scan_index
];
265 if (candidate
== scan_entry
) {
266 // don't check yourself
269 for (dep_index
= 0; dep_index
< scan_entry
->num_dependencies
;
272 /* If the dependency being checked is the candidate,
273 * then the candidate can't be the root.
275 dgraph_entry_t
* check
= scan_entry
->dependencies
[dep_index
];
277 if (check
== candidate
) {
283 /* If the candidate was rejected, then hop out of this loop.
290 /* If we got here, the candidate is a valid one. However, if we already
291 * found another, that means we have two possible roots (or more), which
296 kload_log_error("dependency graph has multiple roots "
297 "(%s and %s)" KNL
, root
->name
, candidate
->name
);
298 return NULL
; // two valid roots, illegal
306 kload_log_error("dependency graph has no root node" KNL
);
312 /*******************************************************************************
314 *******************************************************************************/
315 dgraph_entry_t
** fill_backward_load_order(
316 dgraph_entry_t
** backward_load_order
,
317 unsigned int * list_length
,
318 dgraph_entry_t
* first_entry
,
319 unsigned int * last_index
/* out param */)
322 unsigned int scan_index
= 0;
323 unsigned int add_index
= 0;
324 dgraph_entry_t
* scan_entry
;
326 if (*list_length
== 0) {
327 if (backward_load_order
) {
328 free(backward_load_order
);
329 backward_load_order
= NULL
;
334 backward_load_order
[add_index
++] = first_entry
;
336 while (scan_index
< add_index
) {
338 if (add_index
> 255) {
340 "dependency list for %s ridiculously long; probably a loop" KNL
,
342 if (backward_load_order
) {
343 free(backward_load_order
);
344 backward_load_order
= NULL
;
349 scan_entry
= backward_load_order
[scan_index
++];
351 /* Increase the load order list if needed.
353 if (add_index
+ scan_entry
->num_dependencies
> (*list_length
)) {
355 backward_load_order
= (dgraph_entry_t
**)realloc(
357 (*list_length
) * sizeof(dgraph_entry_t
*));
358 if (!backward_load_order
) {
363 /* Put the dependencies of the scanning entry into the list.
365 for (i
= 0; i
< scan_entry
->num_dependencies
; i
++) {
366 backward_load_order
[add_index
++] =
367 scan_entry
->dependencies
[i
];
374 *last_index
= add_index
;
376 return backward_load_order
;
379 /*******************************************************************************
381 *******************************************************************************/
382 int dgraph_establish_load_order(dgraph_t
* dgraph
) {
383 unsigned int total_dependencies
;
384 unsigned int entry_index
;
385 unsigned int list_index
;
386 unsigned int backward_index
;
387 unsigned int forward_index
;
388 size_t load_order_size
;
389 size_t backward_load_order_size
;
390 dgraph_entry_t
** backward_load_order
;
392 /* Lose the old load_order list. Size can change, so it's easier to just
393 * recreate from scratch.
395 if (dgraph
->load_order
) {
396 free(dgraph
->load_order
);
397 dgraph
->load_order
= NULL
;
400 /* Figure how long the list needs to be to accommodate the max possible
401 * entries from the graph. Duplicates get weeded out, but the list
402 * initially has to accommodate them all.
404 total_dependencies
= dgraph
->length
;
406 for (entry_index
= 0; entry_index
< dgraph
->length
; entry_index
++) {
407 dgraph_entry_t
* curdep
= dgraph
->graph
[entry_index
];
408 total_dependencies
+= curdep
->num_dependencies
;
411 /* Hmm, nothing to do!
413 if (!total_dependencies
) {
417 backward_load_order_size
= total_dependencies
* sizeof(dgraph_entry_t
*);
419 backward_load_order
= (dgraph_entry_t
**)malloc(backward_load_order_size
);
420 if (!backward_load_order
) {
421 kload_log_error("malloc failure" KNL
);
424 bzero(backward_load_order
, backward_load_order_size
);
426 backward_load_order
= fill_backward_load_order(backward_load_order
,
427 &total_dependencies
, dgraph
->root
, &list_index
);
428 if (!backward_load_order
) {
429 kload_log_error("error establishing load order" KNL
);
433 load_order_size
= dgraph
->length
* sizeof(dgraph_entry_t
*);
434 dgraph
->load_order
= (dgraph_entry_t
**)malloc(load_order_size
);
435 if (!dgraph
->load_order
) {
436 kload_log_error("malloc failure" KNL
);
439 bzero(dgraph
->load_order
, load_order_size
);
442 /* Reverse the list into the dgraph's load_order list,
443 * removing any duplicates.
445 backward_index
= list_index
;
447 // the required 1 is taken off in loop below!
451 dgraph_entry_t
* current_entry
;
452 unsigned int already_got_it
= 0;
456 /* Get the entry to check.
458 current_entry
= backward_load_order
[backward_index
];
460 /* Did we already get it?
462 for (list_index
= 0; list_index
< forward_index
; list_index
++) {
463 if (current_entry
== dgraph
->load_order
[list_index
]) {
469 if (already_got_it
) {
473 /* Haven't seen it before; tack it onto the load-order list.
475 dgraph
->load_order
[forward_index
++] = current_entry
;
477 } while (backward_index
> 0);
479 free(backward_load_order
);
484 /*******************************************************************************
486 *******************************************************************************/
487 void dgraph_log(dgraph_t
* depgraph
)
491 kload_log_message("flattened dependency list: " KNL
);
492 for (i
= 0; i
< depgraph
->length
; i
++) {
493 dgraph_entry_t
* current
= depgraph
->graph
[i
];
495 kload_log_message(" %s" KNL
, current
->name
);
496 kload_log_message(" is kernel component: %s" KNL
,
497 current
->is_kernel_component
? "yes" : "no");
498 kload_log_message(" expected kmod name: [%s]" KNL
,
499 current
->expected_kmod_name
);
500 kload_log_message(" expected kmod vers: [%s]" KNL
,
501 current
->expected_kmod_vers
);
503 kload_log_message("" KNL
);
505 kload_log_message("load order dependency list: " KNL
);
506 for (i
= 0; i
< depgraph
->length
; i
++) {
507 dgraph_entry_t
* current
= depgraph
->load_order
[i
];
508 kload_log_message(" %s" KNL
, current
->name
);
510 kload_log_message("" KNL
);
512 kload_log_message("dependency graph: " KNL
);
513 for (i
= 0; i
< depgraph
->length
; i
++) {
514 dgraph_entry_t
* current
= depgraph
->graph
[i
];
515 for (j
= 0; j
< current
->num_dependencies
; j
++) {
516 dgraph_entry_t
* cdep
= current
->dependencies
[j
];
517 kload_log_message(" %s -> %s" KNL
, current
->name
, cdep
->name
);
520 kload_log_message("" KNL
);
525 /*******************************************************************************
527 *******************************************************************************/
528 dgraph_entry_t
* dgraph_find_dependent(dgraph_t
* dgraph
, const char * name
)
532 for (i
= 0; i
< dgraph
->length
; i
++) {
533 dgraph_entry_t
* current_entry
= dgraph
->graph
[i
];
534 if (0 == strcmp(name
, current_entry
->name
)) {
535 return current_entry
;
542 /*******************************************************************************
544 *******************************************************************************/
545 dgraph_entry_t
* dgraph_add_dependent(
550 size_t object_length
,
553 const char * expected_kmod_name
,
554 const char * expected_kmod_vers
,
555 vm_address_t load_address
,
556 char is_kernel_component
)
559 dgraph_entry_t
* found_entry
= NULL
;
560 dgraph_entry_t
* new_entry
= NULL
; // free on error
561 dgraph_entry_t
* the_entry
= NULL
; // returned
563 /* Already got it? Great!
565 found_entry
= dgraph_find_dependent(dgraph
, name
);
567 if (found_entry
->is_kernel_component
!= is_kernel_component
) {
569 "%s is already defined as a %skernel component" KNL
,
570 name
, found_entry
->is_kernel_component
? "" : "non-");
575 if (load_address
!= 0) {
576 if (found_entry
->loaded_address
== 0) {
577 found_entry
->do_load
= 0;
578 found_entry
->loaded_address
= load_address
;
579 } else if (found_entry
->loaded_address
!= load_address
) {
581 "%s has been assigned two different addresses (0x%x, 0x%x) KNL",
583 found_entry
->loaded_address
,
589 the_entry
= found_entry
;
593 /* If the graph is full, make it bigger.
595 if (dgraph
->length
== dgraph
->capacity
) {
596 unsigned int old_capacity
= dgraph
->capacity
;
597 dgraph_entry_t
** newgraph
;
599 dgraph
->capacity
*= 2;
600 newgraph
= (dgraph_entry_t
**)malloc(dgraph
->capacity
*
601 sizeof(dgraph_entry_t
*));
605 memcpy(newgraph
, dgraph
->graph
, old_capacity
* sizeof(dgraph_entry_t
*));
607 dgraph
->graph
= newgraph
;
610 if (strlen(expected_kmod_name
) > KMOD_MAX_NAME
- 1) {
611 kload_log_error("expected kmod name \"%s\" is too long" KNL
,
619 new_entry
= (dgraph_entry_t
*)malloc(sizeof(dgraph_entry_t
));
624 bzero(new_entry
, sizeof(dgraph_entry_t
));
625 new_entry
->expected_kmod_name
= strdup(expected_kmod_name
);
626 if (!new_entry
->expected_kmod_name
) {
630 new_entry
->expected_kmod_vers
= strdup(expected_kmod_vers
);
631 if (!new_entry
->expected_kmod_vers
) {
635 new_entry
->is_kernel_component
= is_kernel_component
;
638 new_entry
->is_symbol_set
= (2 & is_kernel_component
);
640 new_entry
->opaques
= 0;
641 if (!strncmp(new_entry
->expected_kmod_name
,
642 "com.apple.kpi", strlen("com.apple.kpi")))
643 new_entry
->opaques
|= kOpaqueLink
;
644 if (!strcmp(new_entry
->expected_kmod_name
,
646 new_entry
->opaques
|= kOpaqueLink
| kRawKernelLink
;
649 dgraph
->has_symbol_sets
|= new_entry
->is_symbol_set
;
651 new_entry
->do_load
= !is_kernel_component
;
654 new_entry
->object
= NULL
; // provided elswehere in userland
655 new_entry
->object_length
= 0;
657 new_entry
->object
= object
;
658 new_entry
->object_length
= object_length
;
659 new_entry
->object_is_kmem
= object_is_kmem
;
661 new_entry
->name
= strdup(name
);
662 if (!new_entry
->name
) {
666 dgraph
->graph
[dgraph
->length
++] = new_entry
;
669 /* Create a dependency list for the entry. Start with 5 slots.
671 new_entry
->dependencies_capacity
= 5;
672 new_entry
->num_dependencies
= 0;
673 new_entry
->dependencies
= (dgraph_entry_t
**)malloc(
674 new_entry
->dependencies_capacity
* sizeof(dgraph_entry_t
*));
675 if (!new_entry
->dependencies
) {
680 if (new_entry
->loaded_address
== 0) {
681 new_entry
->loaded_address
= load_address
;
682 if (load_address
!= 0) {
683 new_entry
->do_load
= 0;
687 the_entry
= new_entry
;
691 if (new_entry
) __dgraph_entry_free(new_entry
);
692 the_entry
= new_entry
= NULL
;
697 /*******************************************************************************
699 *******************************************************************************/
700 dgraph_entry_t
* dgraph_add_dependency(
702 dgraph_entry_t
* current_dependent
,
706 size_t object_length
,
709 const char * expected_kmod_name
,
710 const char * expected_kmod_vers
,
711 vm_address_t load_address
,
712 char is_kernel_component
)
714 dgraph_entry_t
* dependency
= NULL
;
717 /* If the dependent's dependency list is full, make it bigger.
719 if (current_dependent
->num_dependencies
==
720 current_dependent
->dependencies_capacity
) {
722 unsigned int old_capacity
= current_dependent
->dependencies_capacity
;
723 dgraph_entry_t
** newlist
;
725 current_dependent
->dependencies_capacity
*= 2;
726 newlist
= (dgraph_entry_t
**)malloc(
727 (current_dependent
->dependencies_capacity
*
728 sizeof(dgraph_entry_t
*)) );
733 memcpy(newlist
, current_dependent
->dependencies
,
734 old_capacity
* sizeof(dgraph_entry_t
*));
735 free(current_dependent
->dependencies
);
736 current_dependent
->dependencies
= newlist
;
740 /* Find or add the entry for the new dependency.
742 dependency
= dgraph_add_dependent(dgraph
, name
,
744 object
, object_length
, object_is_kmem
,
746 expected_kmod_name
, expected_kmod_vers
, load_address
,
747 is_kernel_component
);
752 if (dependency
== current_dependent
) {
753 kload_log_error("attempt to set dependency on itself: %s" KNL
,
754 current_dependent
->name
);
758 for (i
= 0; i
< current_dependent
->num_dependencies
; i
++) {
759 dgraph_entry_t
* this_dependency
= current_dependent
->dependencies
[i
];
760 if (this_dependency
== dependency
) {
765 /* Fill in the dependency.
767 current_dependent
->dependencies
[current_dependent
->num_dependencies
] =
769 current_dependent
->num_dependencies
++;
771 current_dependent
->opaque_link
|= dependency
->opaques
;
772 dgraph
->has_opaque_links
|= current_dependent
->opaque_link
;