2 #include <libsa/vers_rsrc.h>
12 #include "vers_rsrc.h"
19 static void __dgraph_entry_free(dgraph_entry_t
* entry
);
22 /*******************************************************************************
24 *******************************************************************************/
25 char * strdup(const char * string
)
30 length
= strlen(string
);
31 dup
= (char *)malloc((1+length
) * sizeof(char));
41 /*******************************************************************************
43 *******************************************************************************/
44 dgraph_error_t
dgraph_init(dgraph_t
* dgraph
)
46 bzero(dgraph
, sizeof(dgraph_t
));
48 dgraph
->capacity
= (5); // pulled from a hat
50 /* Make sure list is big enough & graph has a good start size.
52 dgraph
->graph
= (dgraph_entry_t
**)malloc(
53 dgraph
->capacity
* sizeof(dgraph_entry_t
*));
63 /*******************************************************************************
65 *******************************************************************************/
66 dgraph_error_t
dgraph_init_with_arglist(
69 const char * dependency_delimiter
,
70 const char * kernel_dependency_delimiter
,
74 dgraph_error_t result
= dgraph_valid
;
76 int found_zero_load_address
= 0;
77 int found_nonzero_load_address
= 0;
78 dgraph_entry_t
* current_dependent
= NULL
;
79 char kernel_dependencies
= 0;
81 result
= dgraph_init(dgraph
);
82 if (result
!= dgraph_valid
) {
86 for (i
= 0; i
< argc
; i
++) {
87 vm_address_t load_address
= 0;
89 if (0 == strcmp(argv
[i
], dependency_delimiter
)) {
90 kernel_dependencies
= 0;
91 current_dependent
= NULL
;
93 } else if (0 == strcmp(argv
[i
], kernel_dependency_delimiter
)) {
94 kernel_dependencies
= 1;
95 current_dependent
= NULL
;
99 if (expect_addresses
) {
100 char * address
= rindex(argv
[i
], '@');
102 *address
++ = 0; // snip the address from the filename
103 load_address
= strtoul(address
, NULL
, 0);
107 if (!current_dependent
) {
108 current_dependent
= dgraph_add_dependent(dgraph
, argv
[i
],
109 /* expected kmod name */ NULL
, /* expected vers */ 0,
111 if (!current_dependent
) {
115 if (!dgraph_add_dependency(dgraph
, current_dependent
, argv
[i
],
116 /* expected kmod name */ NULL
, /* expected vers */ 0,
117 load_address
, kernel_dependencies
)) {
124 dgraph
->root
= dgraph_find_root(dgraph
);
125 dgraph_establish_load_order(dgraph
);
128 kload_log_error("dependency graph has no root" KNL
);
129 return dgraph_invalid
;
132 if (dgraph
->root
->is_kernel_component
&& !dgraph
->root
->is_symbol_set
) {
133 kload_log_error("dependency graph root is a kernel component" KNL
);
134 return dgraph_invalid
;
137 for (i
= 0; i
< dgraph
->length
; i
++) {
138 if (dgraph
->graph
[i
]->loaded_address
== 0) {
139 found_zero_load_address
= 1;
141 found_nonzero_load_address
= 1;
144 (found_zero_load_address
&& found_nonzero_load_address
)) {
147 "load addresses must be specified for all module files" KNL
);
148 return dgraph_invalid
;
154 #endif /* not KERNEL */
156 /*******************************************************************************
158 *******************************************************************************/
159 static void __dgraph_entry_free(dgraph_entry_t
* entry
)
165 if (entry
->expected_kmod_name
) {
166 free(entry
->expected_kmod_name
);
167 entry
->expected_kmod_name
= NULL
;
169 if (entry
->expected_kmod_vers
) {
170 free(entry
->expected_kmod_vers
);
171 entry
->expected_kmod_vers
= NULL
;
173 if (entry
->dependencies
) {
174 free(entry
->dependencies
);
175 entry
->dependencies
= NULL
;
177 if (entry
->symbols_malloc
) {
178 free((void *) entry
->symbols_malloc
);
179 entry
->symbols_malloc
= NULL
;
185 /*******************************************************************************
187 *******************************************************************************/
192 unsigned int entry_index
;
198 for (entry_index
= 0; entry_index
< dgraph
->length
; entry_index
++) {
199 dgraph_entry_t
* current
= dgraph
->graph
[entry_index
];
200 __dgraph_entry_free(current
);
205 dgraph
->graph
= NULL
;
208 if (dgraph
->load_order
) {
209 free(dgraph
->load_order
);
210 dgraph
->load_order
= NULL
;
213 if (free_graph
&& dgraph
) {
221 /*******************************************************************************
223 *******************************************************************************/
224 dgraph_entry_t
* dgraph_find_root(dgraph_t
* dgraph
) {
225 dgraph_entry_t
* root
= NULL
;
226 dgraph_entry_t
* candidate
= NULL
;
227 unsigned int candidate_index
;
228 unsigned int scan_index
;
229 unsigned int dep_index
;
232 /* Scan each entry in the graph for one that isn't in any other entry's
235 for (candidate_index
= 0; candidate_index
< dgraph
->length
;
238 candidate
= dgraph
->graph
[candidate_index
];
240 for (scan_index
= 0; scan_index
< dgraph
->length
; scan_index
++) {
242 dgraph_entry_t
* scan_entry
= dgraph
->graph
[scan_index
];
243 if (candidate
== scan_entry
) {
244 // don't check yourself
247 for (dep_index
= 0; dep_index
< scan_entry
->num_dependencies
;
250 /* If the dependency being checked is the candidate,
251 * then the candidate can't be the root.
253 dgraph_entry_t
* check
= scan_entry
->dependencies
[dep_index
];
255 if (check
== candidate
) {
261 /* If the candidate was rejected, then hop out of this loop.
268 /* If we got here, the candidate is a valid one. However, if we already
269 * found another, that means we have two possible roots (or more), which
274 kload_log_error("dependency graph has multiple roots "
275 "(%s and %s)" KNL
, root
->name
, candidate
->name
);
276 return NULL
; // two valid roots, illegal
284 kload_log_error("dependency graph has no root node" KNL
);
290 /*******************************************************************************
292 *******************************************************************************/
293 dgraph_entry_t
** fill_backward_load_order(
294 dgraph_entry_t
** backward_load_order
,
295 unsigned int * list_length
,
296 dgraph_entry_t
* first_entry
,
297 unsigned int * last_index
/* out param */)
300 unsigned int scan_index
= 0;
301 unsigned int add_index
= 0;
302 dgraph_entry_t
* scan_entry
;
304 if (*list_length
== 0) {
305 if (backward_load_order
) {
306 free(backward_load_order
);
307 backward_load_order
= NULL
;
312 backward_load_order
[add_index
++] = first_entry
;
314 while (scan_index
< add_index
) {
316 if (add_index
> 255) {
318 "dependency list for %s ridiculously long; probably a loop" KNL
,
320 if (backward_load_order
) {
321 free(backward_load_order
);
322 backward_load_order
= NULL
;
327 scan_entry
= backward_load_order
[scan_index
++];
329 /* Increase the load order list if needed.
331 if (add_index
+ scan_entry
->num_dependencies
> (*list_length
)) {
333 backward_load_order
= (dgraph_entry_t
**)realloc(
335 (*list_length
) * sizeof(dgraph_entry_t
*));
336 if (!backward_load_order
) {
341 /* Put the dependencies of the scanning entry into the list.
343 for (i
= 0; i
< scan_entry
->num_dependencies
; i
++) {
344 backward_load_order
[add_index
++] =
345 scan_entry
->dependencies
[i
];
352 *last_index
= add_index
;
354 return backward_load_order
;
357 /*******************************************************************************
359 *******************************************************************************/
360 int dgraph_establish_load_order(dgraph_t
* dgraph
) {
361 unsigned int total_dependencies
;
362 unsigned int entry_index
;
363 unsigned int list_index
;
364 unsigned int backward_index
;
365 unsigned int forward_index
;
366 size_t load_order_size
;
367 size_t backward_load_order_size
;
368 dgraph_entry_t
** backward_load_order
;
370 /* Lose the old load_order list. Size can change, so it's easier to just
371 * recreate from scratch.
373 if (dgraph
->load_order
) {
374 free(dgraph
->load_order
);
375 dgraph
->load_order
= NULL
;
378 /* Figure how long the list needs to be to accommodate the max possible
379 * entries from the graph. Duplicates get weeded out, but the list
380 * initially has to accommodate them all.
382 total_dependencies
= dgraph
->length
;
384 for (entry_index
= 0; entry_index
< dgraph
->length
; entry_index
++) {
385 dgraph_entry_t
* curdep
= dgraph
->graph
[entry_index
];
386 total_dependencies
+= curdep
->num_dependencies
;
389 /* Hmm, nothing to do!
391 if (!total_dependencies
) {
395 backward_load_order_size
= total_dependencies
* sizeof(dgraph_entry_t
*);
397 backward_load_order
= (dgraph_entry_t
**)malloc(backward_load_order_size
);
398 if (!backward_load_order
) {
399 kload_log_error("malloc failure" KNL
);
402 bzero(backward_load_order
, backward_load_order_size
);
404 backward_load_order
= fill_backward_load_order(backward_load_order
,
405 &total_dependencies
, dgraph
->root
, &list_index
);
406 if (!backward_load_order
) {
407 kload_log_error("error establishing load order" KNL
);
411 load_order_size
= dgraph
->length
* sizeof(dgraph_entry_t
*);
412 dgraph
->load_order
= (dgraph_entry_t
**)malloc(load_order_size
);
413 if (!dgraph
->load_order
) {
414 kload_log_error("malloc failure" KNL
);
417 bzero(dgraph
->load_order
, load_order_size
);
420 /* Reverse the list into the dgraph's load_order list,
421 * removing any duplicates.
423 backward_index
= list_index
;
425 // the required 1 is taken off in loop below!
429 dgraph_entry_t
* current_entry
;
430 unsigned int already_got_it
= 0;
434 /* Get the entry to check.
436 current_entry
= backward_load_order
[backward_index
];
438 /* Did we already get it?
440 for (list_index
= 0; list_index
< forward_index
; list_index
++) {
441 if (current_entry
== dgraph
->load_order
[list_index
]) {
447 if (already_got_it
) {
451 /* Haven't seen it before; tack it onto the load-order list.
453 dgraph
->load_order
[forward_index
++] = current_entry
;
455 } while (backward_index
> 0);
457 free(backward_load_order
);
462 /*******************************************************************************
464 *******************************************************************************/
465 void dgraph_log(dgraph_t
* depgraph
)
469 kload_log_message("flattened dependency list: " KNL
);
470 for (i
= 0; i
< depgraph
->length
; i
++) {
471 dgraph_entry_t
* current
= depgraph
->graph
[i
];
473 kload_log_message(" %s" KNL
, current
->name
);
474 kload_log_message(" is kernel component: %s" KNL
,
475 current
->is_kernel_component
? "yes" : "no");
476 kload_log_message(" expected kmod name: [%s]" KNL
,
477 current
->expected_kmod_name
);
478 kload_log_message(" expected kmod vers: [%s]" KNL
,
479 current
->expected_kmod_vers
);
481 kload_log_message("" KNL
);
483 kload_log_message("load order dependency list: " KNL
);
484 for (i
= 0; i
< depgraph
->length
; i
++) {
485 dgraph_entry_t
* current
= depgraph
->load_order
[i
];
486 kload_log_message(" %s" KNL
, current
->name
);
488 kload_log_message("" KNL
);
490 kload_log_message("dependency graph: " KNL
);
491 for (i
= 0; i
< depgraph
->length
; i
++) {
492 dgraph_entry_t
* current
= depgraph
->graph
[i
];
493 for (j
= 0; j
< current
->num_dependencies
; j
++) {
494 dgraph_entry_t
* cdep
= current
->dependencies
[j
];
495 kload_log_message(" %s -> %s" KNL
, current
->name
, cdep
->name
);
498 kload_log_message("" KNL
);
503 /*******************************************************************************
505 *******************************************************************************/
506 dgraph_entry_t
* dgraph_find_dependent(dgraph_t
* dgraph
, const char * name
)
510 for (i
= 0; i
< dgraph
->length
; i
++) {
511 dgraph_entry_t
* current_entry
= dgraph
->graph
[i
];
512 if (0 == strcmp(name
, current_entry
->name
)) {
513 return current_entry
;
520 /*******************************************************************************
522 *******************************************************************************/
523 dgraph_entry_t
* dgraph_add_dependent(
528 size_t object_length
,
531 const char * expected_kmod_name
,
532 const char * expected_kmod_vers
,
533 vm_address_t load_address
,
534 char is_kernel_component
)
537 dgraph_entry_t
* found_entry
= NULL
;
538 dgraph_entry_t
* new_entry
= NULL
; // free on error
539 dgraph_entry_t
* the_entry
= NULL
; // returned
541 /* Already got it? Great!
543 found_entry
= dgraph_find_dependent(dgraph
, name
);
545 if (found_entry
->is_kernel_component
!= is_kernel_component
) {
547 "%s is already defined as a %skernel component" KNL
,
548 name
, found_entry
->is_kernel_component
? "" : "non-");
553 if (load_address
!= 0) {
554 if (found_entry
->loaded_address
== 0) {
555 found_entry
->do_load
= 0;
556 found_entry
->loaded_address
= load_address
;
557 } else if (found_entry
->loaded_address
!= load_address
) {
559 "%s has been assigned two different addresses (0x%x, 0x%x) KNL",
561 found_entry
->loaded_address
,
567 the_entry
= found_entry
;
571 /* If the graph is full, make it bigger.
573 if (dgraph
->length
== dgraph
->capacity
) {
574 unsigned int old_capacity
= dgraph
->capacity
;
575 dgraph_entry_t
** newgraph
;
577 dgraph
->capacity
*= 2;
578 newgraph
= (dgraph_entry_t
**)malloc(dgraph
->capacity
*
579 sizeof(dgraph_entry_t
*));
583 memcpy(newgraph
, dgraph
->graph
, old_capacity
* sizeof(dgraph_entry_t
*));
585 dgraph
->graph
= newgraph
;
588 if (strlen(expected_kmod_name
) > KMOD_MAX_NAME
- 1) {
589 kload_log_error("expected kmod name \"%s\" is too long" KNL
,
597 new_entry
= (dgraph_entry_t
*)malloc(sizeof(dgraph_entry_t
));
602 bzero(new_entry
, sizeof(dgraph_entry_t
));
603 new_entry
->expected_kmod_name
= strdup(expected_kmod_name
);
604 if (!new_entry
->expected_kmod_name
) {
608 new_entry
->expected_kmod_vers
= strdup(expected_kmod_vers
);
609 if (!new_entry
->expected_kmod_vers
) {
613 new_entry
->is_kernel_component
= is_kernel_component
;
616 new_entry
->is_symbol_set
= (2 & is_kernel_component
);
617 new_entry
->opaques
= !strncmp(new_entry
->expected_kmod_name
,
618 "com.apple.kpi", strlen("com.apple.kpi"));
621 dgraph
->has_symbol_sets
|= new_entry
->is_symbol_set
;
623 new_entry
->do_load
= !is_kernel_component
;
626 new_entry
->object
= NULL
; // provided elswehere in userland
627 new_entry
->object_length
= 0;
629 new_entry
->object
= object
;
630 new_entry
->object_length
= object_length
;
631 new_entry
->object_is_kmem
= object_is_kmem
;
633 new_entry
->name
= strdup(name
);
634 if (!new_entry
->name
) {
638 dgraph
->graph
[dgraph
->length
++] = new_entry
;
641 /* Create a dependency list for the entry. Start with 5 slots.
643 new_entry
->dependencies_capacity
= 5;
644 new_entry
->num_dependencies
= 0;
645 new_entry
->dependencies
= (dgraph_entry_t
**)malloc(
646 new_entry
->dependencies_capacity
* sizeof(dgraph_entry_t
*));
647 if (!new_entry
->dependencies
) {
652 if (new_entry
->loaded_address
== 0) {
653 new_entry
->loaded_address
= load_address
;
654 if (load_address
!= 0) {
655 new_entry
->do_load
= 0;
659 the_entry
= new_entry
;
663 if (new_entry
) __dgraph_entry_free(new_entry
);
664 the_entry
= new_entry
= NULL
;
669 /*******************************************************************************
671 *******************************************************************************/
672 dgraph_entry_t
* dgraph_add_dependency(
674 dgraph_entry_t
* current_dependent
,
678 size_t object_length
,
681 const char * expected_kmod_name
,
682 const char * expected_kmod_vers
,
683 vm_address_t load_address
,
684 char is_kernel_component
)
686 dgraph_entry_t
* dependency
= NULL
;
689 /* If the dependent's dependency list is full, make it bigger.
691 if (current_dependent
->num_dependencies
==
692 current_dependent
->dependencies_capacity
) {
694 unsigned int old_capacity
= current_dependent
->dependencies_capacity
;
695 dgraph_entry_t
** newlist
;
697 current_dependent
->dependencies_capacity
*= 2;
698 newlist
= (dgraph_entry_t
**)malloc(
699 (current_dependent
->dependencies_capacity
*
700 sizeof(dgraph_entry_t
*)) );
705 memcpy(newlist
, current_dependent
->dependencies
,
706 old_capacity
* sizeof(dgraph_entry_t
*));
707 free(current_dependent
->dependencies
);
708 current_dependent
->dependencies
= newlist
;
712 /* Find or add the entry for the new dependency.
714 dependency
= dgraph_add_dependent(dgraph
, name
,
716 object
, object_length
, object_is_kmem
,
718 expected_kmod_name
, expected_kmod_vers
, load_address
,
719 is_kernel_component
);
724 if (dependency
== current_dependent
) {
725 kload_log_error("attempt to set dependency on itself: %s" KNL
,
726 current_dependent
->name
);
730 for (i
= 0; i
< current_dependent
->num_dependencies
; i
++) {
731 dgraph_entry_t
* this_dependency
= current_dependent
->dependencies
[i
];
732 if (this_dependency
== dependency
) {
737 /* Fill in the dependency.
739 current_dependent
->dependencies
[current_dependent
->num_dependencies
] =
741 current_dependent
->num_dependencies
++;
743 current_dependent
->opaque_link
|= dependency
->opaques
;
744 dgraph
->has_opaque_links
|= current_dependent
->opaque_link
;