2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <libsa/vers_rsrc.h>
40 #include "vers_rsrc.h"
47 #include <sys/malloc.h>
50 static void __dgraph_entry_free(dgraph_entry_t
* entry
);
53 #define dgstrdup(string) STRDUP(string, M_TEMP)
54 #define dgfree(string) FREE(string, M_TEMP)
56 #define dgstrdup strdup
57 #define dgfree(string) free(string)
60 /*******************************************************************************
62 *******************************************************************************/
63 dgraph_error_t
dgraph_init(dgraph_t
* dgraph
)
65 bzero(dgraph
, sizeof(dgraph_t
));
67 dgraph
->capacity
= (5); // pulled from a hat
69 /* Make sure list is big enough & graph has a good start size.
71 dgraph
->graph
= (dgraph_entry_t
**)malloc(
72 dgraph
->capacity
* sizeof(dgraph_entry_t
*));
82 /*******************************************************************************
84 *******************************************************************************/
85 dgraph_error_t
dgraph_init_with_arglist(
88 const char * dependency_delimiter
,
89 const char * kernel_dependency_delimiter
,
93 dgraph_error_t result
= dgraph_valid
;
95 int found_zero_load_address
= 0;
96 int found_nonzero_load_address
= 0;
97 dgraph_entry_t
* current_dependent
= NULL
;
98 char kernel_dependencies
= 0;
100 result
= dgraph_init(dgraph
);
101 if (result
!= dgraph_valid
) {
105 for (i
= 0; i
< argc
; i
++) {
106 vm_address_t load_address
= 0;
108 if (0 == strcmp(argv
[i
], dependency_delimiter
)) {
109 kernel_dependencies
= 0;
110 current_dependent
= NULL
;
112 } else if (0 == strcmp(argv
[i
], kernel_dependency_delimiter
)) {
113 kernel_dependencies
= 1;
114 current_dependent
= NULL
;
118 if (expect_addresses
) {
119 char * address
= rindex(argv
[i
], '@');
121 *address
++ = 0; // snip the address from the filename
122 load_address
= strtoul(address
, NULL
, 0);
126 if (!current_dependent
) {
127 current_dependent
= dgraph_add_dependent(dgraph
, argv
[i
],
128 /* expected kmod name */ NULL
, /* expected vers */ 0,
130 if (!current_dependent
) {
134 if (!dgraph_add_dependency(dgraph
, current_dependent
, argv
[i
],
135 /* expected kmod name */ NULL
, /* expected vers */ 0,
136 load_address
, kernel_dependencies
)) {
143 dgraph
->root
= dgraph_find_root(dgraph
);
144 dgraph_establish_load_order(dgraph
);
147 kload_log_error("dependency graph has no root" KNL
);
148 return dgraph_invalid
;
151 if (dgraph
->root
->is_kernel_component
&& !dgraph
->root
->is_symbol_set
) {
152 kload_log_error("dependency graph root is a kernel component" KNL
);
153 return dgraph_invalid
;
156 for (i
= 0; i
< dgraph
->length
; i
++) {
157 if (dgraph
->graph
[i
]->loaded_address
== 0) {
158 found_zero_load_address
= 1;
160 found_nonzero_load_address
= 1;
163 (found_zero_load_address
&& found_nonzero_load_address
)) {
166 "load addresses must be specified for all module files" KNL
);
167 return dgraph_invalid
;
173 #endif /* not KERNEL */
175 /*******************************************************************************
177 *******************************************************************************/
178 static void __dgraph_entry_free(dgraph_entry_t
* entry
)
184 if (entry
->expected_kmod_name
) {
185 dgfree(entry
->expected_kmod_name
);
186 entry
->expected_kmod_name
= NULL
;
188 if (entry
->expected_kmod_vers
) {
189 dgfree(entry
->expected_kmod_vers
);
190 entry
->expected_kmod_vers
= NULL
;
192 if (entry
->dependencies
) {
193 free(entry
->dependencies
);
194 entry
->dependencies
= NULL
;
196 if (entry
->symbols_malloc
) {
197 free((void *) entry
->symbols_malloc
);
198 entry
->symbols_malloc
= 0;
204 /*******************************************************************************
206 *******************************************************************************/
211 unsigned int entry_index
;
217 for (entry_index
= 0; entry_index
< dgraph
->length
; entry_index
++) {
218 dgraph_entry_t
* current
= dgraph
->graph
[entry_index
];
219 __dgraph_entry_free(current
);
224 dgraph
->graph
= NULL
;
227 if (dgraph
->load_order
) {
228 free(dgraph
->load_order
);
229 dgraph
->load_order
= NULL
;
232 if (free_graph
&& dgraph
) {
240 /*******************************************************************************
242 *******************************************************************************/
243 dgraph_entry_t
* dgraph_find_root(dgraph_t
* dgraph
) {
244 dgraph_entry_t
* root
= NULL
;
245 dgraph_entry_t
* candidate
= NULL
;
246 unsigned int candidate_index
;
247 unsigned int scan_index
;
248 unsigned int dep_index
;
251 /* Scan each entry in the graph for one that isn't in any other entry's
254 for (candidate_index
= 0; candidate_index
< dgraph
->length
;
257 candidate
= dgraph
->graph
[candidate_index
];
259 for (scan_index
= 0; scan_index
< dgraph
->length
; scan_index
++) {
261 dgraph_entry_t
* scan_entry
= dgraph
->graph
[scan_index
];
262 if (candidate
== scan_entry
) {
263 // don't check yourself
266 for (dep_index
= 0; dep_index
< scan_entry
->num_dependencies
;
269 /* If the dependency being checked is the candidate,
270 * then the candidate can't be the root.
272 dgraph_entry_t
* check
= scan_entry
->dependencies
[dep_index
];
274 if (check
== candidate
) {
280 /* If the candidate was rejected, then hop out of this loop.
287 /* If we got here, the candidate is a valid one. However, if we already
288 * found another, that means we have two possible roots (or more), which
293 kload_log_error("dependency graph has multiple roots "
294 "(%s and %s)" KNL
, root
->name
, candidate
->name
);
295 return NULL
; // two valid roots, illegal
303 kload_log_error("dependency graph has no root node" KNL
);
309 /*******************************************************************************
311 *******************************************************************************/
312 dgraph_entry_t
** fill_backward_load_order(
313 dgraph_entry_t
** backward_load_order
,
314 unsigned int * list_length
,
315 dgraph_entry_t
* first_entry
,
316 unsigned int * last_index
/* out param */)
319 unsigned int scan_index
= 0;
320 unsigned int add_index
= 0;
321 dgraph_entry_t
* scan_entry
;
323 if (*list_length
== 0) {
324 if (backward_load_order
) {
325 free(backward_load_order
);
326 backward_load_order
= NULL
;
331 backward_load_order
[add_index
++] = first_entry
;
333 while (scan_index
< add_index
) {
335 if (add_index
> 255) {
337 "dependency list for %s ridiculously long; probably a loop" KNL
,
339 if (backward_load_order
) {
340 free(backward_load_order
);
341 backward_load_order
= NULL
;
346 scan_entry
= backward_load_order
[scan_index
++];
348 /* Increase the load order list if needed.
350 if (add_index
+ scan_entry
->num_dependencies
> (*list_length
)) {
352 backward_load_order
= (dgraph_entry_t
**)realloc(
354 (*list_length
) * sizeof(dgraph_entry_t
*));
355 if (!backward_load_order
) {
360 /* Put the dependencies of the scanning entry into the list.
362 for (i
= 0; i
< scan_entry
->num_dependencies
; i
++) {
363 backward_load_order
[add_index
++] =
364 scan_entry
->dependencies
[i
];
371 *last_index
= add_index
;
373 return backward_load_order
;
376 /*******************************************************************************
378 *******************************************************************************/
379 int dgraph_establish_load_order(dgraph_t
* dgraph
) {
380 unsigned int total_dependencies
;
381 unsigned int entry_index
;
382 unsigned int list_index
;
383 unsigned int backward_index
;
384 unsigned int forward_index
;
385 size_t load_order_size
;
386 size_t backward_load_order_size
;
387 dgraph_entry_t
** backward_load_order
;
389 /* Lose the old load_order list. Size can change, so it's easier to just
390 * recreate from scratch.
392 if (dgraph
->load_order
) {
393 free(dgraph
->load_order
);
394 dgraph
->load_order
= NULL
;
397 /* Figure how long the list needs to be to accommodate the max possible
398 * entries from the graph. Duplicates get weeded out, but the list
399 * initially has to accommodate them all.
401 total_dependencies
= dgraph
->length
;
403 for (entry_index
= 0; entry_index
< dgraph
->length
; entry_index
++) {
404 dgraph_entry_t
* curdep
= dgraph
->graph
[entry_index
];
405 total_dependencies
+= curdep
->num_dependencies
;
408 /* Hmm, nothing to do!
410 if (!total_dependencies
) {
414 backward_load_order_size
= total_dependencies
* sizeof(dgraph_entry_t
*);
416 backward_load_order
= (dgraph_entry_t
**)malloc(backward_load_order_size
);
417 if (!backward_load_order
) {
418 kload_log_error("malloc failure" KNL
);
421 bzero(backward_load_order
, backward_load_order_size
);
423 backward_load_order
= fill_backward_load_order(backward_load_order
,
424 &total_dependencies
, dgraph
->root
, &list_index
);
425 if (!backward_load_order
) {
426 kload_log_error("error establishing load order" KNL
);
430 load_order_size
= dgraph
->length
* sizeof(dgraph_entry_t
*);
431 dgraph
->load_order
= (dgraph_entry_t
**)malloc(load_order_size
);
432 if (!dgraph
->load_order
) {
433 kload_log_error("malloc failure" KNL
);
436 bzero(dgraph
->load_order
, load_order_size
);
439 /* Reverse the list into the dgraph's load_order list,
440 * removing any duplicates.
442 backward_index
= list_index
;
444 // the required 1 is taken off in loop below!
448 dgraph_entry_t
* current_entry
;
449 unsigned int already_got_it
= 0;
453 /* Get the entry to check.
455 current_entry
= backward_load_order
[backward_index
];
457 /* Did we already get it?
459 for (list_index
= 0; list_index
< forward_index
; list_index
++) {
460 if (current_entry
== dgraph
->load_order
[list_index
]) {
466 if (already_got_it
) {
470 /* Haven't seen it before; tack it onto the load-order list.
472 dgraph
->load_order
[forward_index
++] = current_entry
;
474 } while (backward_index
> 0);
476 free(backward_load_order
);
481 /*******************************************************************************
483 *******************************************************************************/
484 void dgraph_log(dgraph_t
* depgraph
)
488 kload_log_message("flattened dependency list: " KNL
);
489 for (i
= 0; i
< depgraph
->length
; i
++) {
490 dgraph_entry_t
* current
= depgraph
->graph
[i
];
492 kload_log_message(" %s" KNL
, current
->name
);
493 kload_log_message(" is kernel component: %s" KNL
,
494 current
->is_kernel_component
? "yes" : "no");
495 kload_log_message(" expected kmod name: [%s]" KNL
,
496 current
->expected_kmod_name
);
497 kload_log_message(" expected kmod vers: [%s]" KNL
,
498 current
->expected_kmod_vers
);
500 kload_log_message("" KNL
);
502 kload_log_message("load order dependency list: " KNL
);
503 for (i
= 0; i
< depgraph
->length
; i
++) {
504 dgraph_entry_t
* current
= depgraph
->load_order
[i
];
505 kload_log_message(" %s" KNL
, current
->name
);
507 kload_log_message("" KNL
);
509 kload_log_message("dependency graph: " KNL
);
510 for (i
= 0; i
< depgraph
->length
; i
++) {
511 dgraph_entry_t
* current
= depgraph
->graph
[i
];
512 for (j
= 0; j
< current
->num_dependencies
; j
++) {
513 dgraph_entry_t
* cdep
= current
->dependencies
[j
];
514 kload_log_message(" %s -> %s" KNL
, current
->name
, cdep
->name
);
517 kload_log_message("" KNL
);
522 /*******************************************************************************
524 *******************************************************************************/
525 dgraph_entry_t
* dgraph_find_dependent(dgraph_t
* dgraph
, const char * name
)
529 for (i
= 0; i
< dgraph
->length
; i
++) {
530 dgraph_entry_t
* current_entry
= dgraph
->graph
[i
];
531 if (0 == strcmp(name
, current_entry
->name
)) {
532 return current_entry
;
539 /*******************************************************************************
541 *******************************************************************************/
542 dgraph_entry_t
* dgraph_add_dependent(
547 size_t object_length
,
550 kmod_args_t user_data
,
551 mach_msg_type_number_t user_data_length
,
554 const char * expected_kmod_name
,
555 const char * expected_kmod_vers
,
556 vm_address_t load_address
,
557 char is_kernel_component
)
560 dgraph_entry_t
* found_entry
= NULL
;
561 dgraph_entry_t
* new_entry
= NULL
; // free on error
562 dgraph_entry_t
* the_entry
= NULL
; // returned
564 /* Already got it? Great!
566 found_entry
= dgraph_find_dependent(dgraph
, name
);
568 if (found_entry
->is_kernel_component
!= is_kernel_component
) {
570 "%s is already defined as a %skernel component" KNL
,
571 name
, found_entry
->is_kernel_component
? "" : "non-");
576 if (load_address
!= 0) {
577 if (found_entry
->loaded_address
== 0) {
578 found_entry
->do_load
= 0;
579 found_entry
->loaded_address
= load_address
;
580 } else if (found_entry
->loaded_address
!= load_address
) {
582 "%s has been assigned two different addresses (0x%x, 0x%x) KNL",
584 found_entry
->loaded_address
,
590 the_entry
= found_entry
;
594 /* If the graph is full, make it bigger.
596 if (dgraph
->length
== dgraph
->capacity
) {
597 unsigned int old_capacity
= dgraph
->capacity
;
598 dgraph_entry_t
** newgraph
;
600 dgraph
->capacity
*= 2;
601 newgraph
= (dgraph_entry_t
**)malloc(dgraph
->capacity
*
602 sizeof(dgraph_entry_t
*));
606 memcpy(newgraph
, dgraph
->graph
, old_capacity
* sizeof(dgraph_entry_t
*));
608 dgraph
->graph
= newgraph
;
611 if (strlen(expected_kmod_name
) > KMOD_MAX_NAME
- 1) {
612 kload_log_error("expected kmod name \"%s\" is too long" KNL
,
620 new_entry
= (dgraph_entry_t
*)malloc(sizeof(dgraph_entry_t
));
625 bzero(new_entry
, sizeof(dgraph_entry_t
));
626 new_entry
->expected_kmod_name
= dgstrdup(expected_kmod_name
);
627 if (!new_entry
->expected_kmod_name
) {
631 new_entry
->expected_kmod_vers
= dgstrdup(expected_kmod_vers
);
632 if (!new_entry
->expected_kmod_vers
) {
636 new_entry
->is_kernel_component
= is_kernel_component
;
639 new_entry
->is_symbol_set
= (2 & is_kernel_component
);
641 new_entry
->opaques
= 0;
642 if (!strncmp(new_entry
->expected_kmod_name
,
643 "com.apple.kpi", strlen("com.apple.kpi")))
644 new_entry
->opaques
|= kOpaqueLink
;
645 if (!strcmp(new_entry
->expected_kmod_name
,
647 new_entry
->opaques
|= kOpaqueLink
| kRawKernelLink
;
650 dgraph
->has_symbol_sets
|= new_entry
->is_symbol_set
;
652 new_entry
->do_load
= !is_kernel_component
;
655 new_entry
->object
= NULL
; // provided elswehere in userland
656 new_entry
->object_length
= 0;
658 new_entry
->object
= object
;
659 new_entry
->object_length
= object_length
;
660 new_entry
->object_is_kmem
= object_is_kmem
;
662 new_entry
->user_data
= user_data
;
663 new_entry
->user_data_length
= user_data_length
;
666 new_entry
->name
= dgstrdup(name
);
667 if (!new_entry
->name
) {
671 dgraph
->graph
[dgraph
->length
++] = new_entry
;
674 /* Create a dependency list for the entry. Start with 5 slots.
676 new_entry
->dependencies_capacity
= 5;
677 new_entry
->num_dependencies
= 0;
678 new_entry
->dependencies
= (dgraph_entry_t
**)malloc(
679 new_entry
->dependencies_capacity
* sizeof(dgraph_entry_t
*));
680 if (!new_entry
->dependencies
) {
685 if (new_entry
->loaded_address
== 0) {
686 new_entry
->loaded_address
= load_address
;
687 if (load_address
!= 0) {
688 new_entry
->do_load
= 0;
692 the_entry
= new_entry
;
696 if (new_entry
) __dgraph_entry_free(new_entry
);
697 the_entry
= new_entry
= NULL
;
702 /*******************************************************************************
704 *******************************************************************************/
705 dgraph_entry_t
* dgraph_add_dependency(
707 dgraph_entry_t
* current_dependent
,
711 size_t object_length
,
714 kmod_args_t user_data
,
715 mach_msg_type_number_t user_data_length
,
718 const char * expected_kmod_name
,
719 const char * expected_kmod_vers
,
720 vm_address_t load_address
,
721 char is_kernel_component
)
723 dgraph_entry_t
* dependency
= NULL
;
726 /* If the dependent's dependency list is full, make it bigger.
728 if (current_dependent
->num_dependencies
==
729 current_dependent
->dependencies_capacity
) {
731 unsigned int old_capacity
= current_dependent
->dependencies_capacity
;
732 dgraph_entry_t
** newlist
;
734 current_dependent
->dependencies_capacity
*= 2;
735 newlist
= (dgraph_entry_t
**)malloc(
736 (current_dependent
->dependencies_capacity
*
737 sizeof(dgraph_entry_t
*)) );
742 memcpy(newlist
, current_dependent
->dependencies
,
743 old_capacity
* sizeof(dgraph_entry_t
*));
744 free(current_dependent
->dependencies
);
745 current_dependent
->dependencies
= newlist
;
749 /* Find or add the entry for the new dependency.
751 dependency
= dgraph_add_dependent(dgraph
, name
,
753 object
, object_length
, object_is_kmem
,
755 user_data
, user_data_length
,
758 expected_kmod_name
, expected_kmod_vers
, load_address
,
759 is_kernel_component
);
764 if (dependency
== current_dependent
) {
765 kload_log_error("attempt to set dependency on itself: %s" KNL
,
766 current_dependent
->name
);
770 for (i
= 0; i
< current_dependent
->num_dependencies
; i
++) {
771 dgraph_entry_t
* this_dependency
= current_dependent
->dependencies
[i
];
772 if (this_dependency
== dependency
) {
777 /* Fill in the dependency.
779 current_dependent
->dependencies
[current_dependent
->num_dependencies
] =
781 current_dependent
->num_dependencies
++;
783 current_dependent
->opaque_link
|= dependency
->opaques
;
784 dgraph
->has_opaque_links
|= current_dependent
->opaque_link
;