]> git.saurik.com Git - apple/xnu.git/blob - libsa/dgraph.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / libsa / dgraph.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #ifdef KERNEL
30 #include <libsa/vers_rsrc.h>
31 #else
32 #include <libc.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include "KXKext.h"
40 #include "vers_rsrc.h"
41 #endif /* KERNEL */
42
43 #include "dgraph.h"
44 #include "load.h"
45
46
47 static void __dgraph_entry_free(dgraph_entry_t * entry);
48
49 #ifdef KERNEL
50 /*******************************************************************************
51 *
52 *******************************************************************************/
53 char * strdup(const char * string)
54 {
55 char * dup = 0;
56 unsigned int length;
57
58 length = strlen(string);
59 dup = (char *)malloc((1+length) * sizeof(char));
60 if (!dup) {
61 return NULL;
62 }
63 strcpy(dup, string);
64 return dup;
65 }
66
67 #endif /* KERNEL */
68
69 /*******************************************************************************
70 *
71 *******************************************************************************/
72 dgraph_error_t dgraph_init(dgraph_t * dgraph)
73 {
74 bzero(dgraph, sizeof(dgraph_t));
75
76 dgraph->capacity = (5); // pulled from a hat
77
78 /* Make sure list is big enough & graph has a good start size.
79 */
80 dgraph->graph = (dgraph_entry_t **)malloc(
81 dgraph->capacity * sizeof(dgraph_entry_t *));
82
83 if (!dgraph->graph) {
84 return dgraph_error;
85 }
86
87 return dgraph_valid;
88 }
89
90 #ifndef KERNEL
91 /*******************************************************************************
92 *
93 *******************************************************************************/
94 dgraph_error_t dgraph_init_with_arglist(
95 dgraph_t * dgraph,
96 int expect_addresses,
97 const char * dependency_delimiter,
98 const char * kernel_dependency_delimiter,
99 int argc,
100 char * argv[])
101 {
102 dgraph_error_t result = dgraph_valid;
103 unsigned int i;
104 int found_zero_load_address = 0;
105 int found_nonzero_load_address = 0;
106 dgraph_entry_t * current_dependent = NULL;
107 char kernel_dependencies = 0;
108
109 result = dgraph_init(dgraph);
110 if (result != dgraph_valid) {
111 return result;
112 }
113
114 for (i = 0; i < argc; i++) {
115 vm_address_t load_address = 0;
116
117 if (0 == strcmp(argv[i], dependency_delimiter)) {
118 kernel_dependencies = 0;
119 current_dependent = NULL;
120 continue;
121 } else if (0 == strcmp(argv[i], kernel_dependency_delimiter)) {
122 kernel_dependencies = 1;
123 current_dependent = NULL;
124 continue;
125 }
126
127 if (expect_addresses) {
128 char * address = rindex(argv[i], '@');
129 if (address) {
130 *address++ = 0; // snip the address from the filename
131 load_address = strtoul(address, NULL, 0);
132 }
133 }
134
135 if (!current_dependent) {
136 current_dependent = dgraph_add_dependent(dgraph, argv[i],
137 /* expected kmod name */ NULL, /* expected vers */ 0,
138 load_address, 0);
139 if (!current_dependent) {
140 return dgraph_error;
141 }
142 } else {
143 if (!dgraph_add_dependency(dgraph, current_dependent, argv[i],
144 /* expected kmod name */ NULL, /* expected vers */ 0,
145 load_address, kernel_dependencies)) {
146
147 return dgraph_error;
148 }
149 }
150 }
151
152 dgraph->root = dgraph_find_root(dgraph);
153 dgraph_establish_load_order(dgraph);
154
155 if (!dgraph->root) {
156 kload_log_error("dependency graph has no root" KNL);
157 return dgraph_invalid;
158 }
159
160 if (dgraph->root->is_kernel_component && !dgraph->root->is_symbol_set) {
161 kload_log_error("dependency graph root is a kernel component" KNL);
162 return dgraph_invalid;
163 }
164
165 for (i = 0; i < dgraph->length; i++) {
166 if (dgraph->graph[i]->loaded_address == 0) {
167 found_zero_load_address = 1;
168 } else {
169 found_nonzero_load_address = 1;
170 }
171 if ( (i > 0) &&
172 (found_zero_load_address && found_nonzero_load_address)) {
173
174 kload_log_error(
175 "load addresses must be specified for all module files" KNL);
176 return dgraph_invalid;
177 }
178 }
179
180 return dgraph_valid;
181 }
182 #endif /* not KERNEL */
183
184 /*******************************************************************************
185 *
186 *******************************************************************************/
187 static void __dgraph_entry_free(dgraph_entry_t * entry)
188 {
189 if (entry->name) {
190 free(entry->name);
191 entry->name = NULL;
192 }
193 if (entry->expected_kmod_name) {
194 free(entry->expected_kmod_name);
195 entry->expected_kmod_name = NULL;
196 }
197 if (entry->expected_kmod_vers) {
198 free(entry->expected_kmod_vers);
199 entry->expected_kmod_vers = NULL;
200 }
201 if (entry->dependencies) {
202 free(entry->dependencies);
203 entry->dependencies = NULL;
204 }
205 if (entry->symbols_malloc) {
206 free((void *) entry->symbols_malloc);
207 entry->symbols_malloc = NULL;
208 }
209 free(entry);
210 return;
211 }
212
213 /*******************************************************************************
214 *
215 *******************************************************************************/
216 void dgraph_free(
217 dgraph_t * dgraph,
218 int free_graph)
219 {
220 unsigned int entry_index;
221
222 if (!dgraph) {
223 return;
224 }
225
226 for (entry_index = 0; entry_index < dgraph->length; entry_index++) {
227 dgraph_entry_t * current = dgraph->graph[entry_index];
228 __dgraph_entry_free(current);
229 }
230
231 if (dgraph->graph) {
232 free(dgraph->graph);
233 dgraph->graph = NULL;
234 }
235
236 if (dgraph->load_order) {
237 free(dgraph->load_order);
238 dgraph->load_order = NULL;
239 }
240
241 if (free_graph && dgraph) {
242 free(dgraph);
243 }
244
245 return;
246 }
247
248
249 /*******************************************************************************
250 *
251 *******************************************************************************/
252 dgraph_entry_t * dgraph_find_root(dgraph_t * dgraph) {
253 dgraph_entry_t * root = NULL;
254 dgraph_entry_t * candidate = NULL;
255 unsigned int candidate_index;
256 unsigned int scan_index;
257 unsigned int dep_index;
258
259
260 /* Scan each entry in the graph for one that isn't in any other entry's
261 * dependencies.
262 */
263 for (candidate_index = 0; candidate_index < dgraph->length;
264 candidate_index++) {
265
266 candidate = dgraph->graph[candidate_index];
267
268 for (scan_index = 0; scan_index < dgraph->length; scan_index++) {
269
270 dgraph_entry_t * scan_entry = dgraph->graph[scan_index];
271 if (candidate == scan_entry) {
272 // don't check yourself
273 continue;
274 }
275 for (dep_index = 0; dep_index < scan_entry->num_dependencies;
276 dep_index++) {
277
278 /* If the dependency being checked is the candidate,
279 * then the candidate can't be the root.
280 */
281 dgraph_entry_t * check = scan_entry->dependencies[dep_index];
282
283 if (check == candidate) {
284 candidate = NULL;
285 break;
286 }
287 }
288
289 /* If the candidate was rejected, then hop out of this loop.
290 */
291 if (!candidate) {
292 break;
293 }
294 }
295
296 /* If we got here, the candidate is a valid one. However, if we already
297 * found another, that means we have two possible roots (or more), which
298 * is NOT ALLOWED.
299 */
300 if (candidate) {
301 if (root) {
302 kload_log_error("dependency graph has multiple roots "
303 "(%s and %s)" KNL, root->name, candidate->name);
304 return NULL; // two valid roots, illegal
305 } else {
306 root = candidate;
307 }
308 }
309 }
310
311 if (!root) {
312 kload_log_error("dependency graph has no root node" KNL);
313 }
314
315 return root;
316 }
317
318 /*******************************************************************************
319 *
320 *******************************************************************************/
321 dgraph_entry_t ** fill_backward_load_order(
322 dgraph_entry_t ** backward_load_order,
323 unsigned int * list_length,
324 dgraph_entry_t * first_entry,
325 unsigned int * last_index /* out param */)
326 {
327 int i;
328 unsigned int scan_index = 0;
329 unsigned int add_index = 0;
330 dgraph_entry_t * scan_entry;
331
332 if (*list_length == 0) {
333 if (backward_load_order) {
334 free(backward_load_order);
335 backward_load_order = NULL;
336 }
337 goto finish;
338 }
339
340 backward_load_order[add_index++] = first_entry;
341
342 while (scan_index < add_index) {
343
344 if (add_index > 255) {
345 kload_log_error(
346 "dependency list for %s ridiculously long; probably a loop" KNL,
347 first_entry->name);
348 if (backward_load_order) {
349 free(backward_load_order);
350 backward_load_order = NULL;
351 }
352 goto finish;
353 }
354
355 scan_entry = backward_load_order[scan_index++];
356
357 /* Increase the load order list if needed.
358 */
359 if (add_index + scan_entry->num_dependencies > (*list_length)) {
360 (*list_length) *= 2;
361 backward_load_order = (dgraph_entry_t **)realloc(
362 backward_load_order,
363 (*list_length) * sizeof(dgraph_entry_t *));
364 if (!backward_load_order) {
365 goto finish;
366 }
367 }
368
369 /* Put the dependencies of the scanning entry into the list.
370 */
371 for (i = 0; i < scan_entry->num_dependencies; i++) {
372 backward_load_order[add_index++] =
373 scan_entry->dependencies[i];
374 }
375 }
376
377 finish:
378
379 if (last_index) {
380 *last_index = add_index;
381 }
382 return backward_load_order;
383 }
384
385 /*******************************************************************************
386 *
387 *******************************************************************************/
388 int dgraph_establish_load_order(dgraph_t * dgraph) {
389 unsigned int total_dependencies;
390 unsigned int entry_index;
391 unsigned int list_index;
392 unsigned int backward_index;
393 unsigned int forward_index;
394 size_t load_order_size;
395 size_t backward_load_order_size;
396 dgraph_entry_t ** backward_load_order;
397
398 /* Lose the old load_order list. Size can change, so it's easier to just
399 * recreate from scratch.
400 */
401 if (dgraph->load_order) {
402 free(dgraph->load_order);
403 dgraph->load_order = NULL;
404 }
405
406 /* Figure how long the list needs to be to accommodate the max possible
407 * entries from the graph. Duplicates get weeded out, but the list
408 * initially has to accommodate them all.
409 */
410 total_dependencies = dgraph->length;
411
412 for (entry_index = 0; entry_index < dgraph->length; entry_index ++) {
413 dgraph_entry_t * curdep = dgraph->graph[entry_index];
414 total_dependencies += curdep->num_dependencies;
415 }
416
417 /* Hmm, nothing to do!
418 */
419 if (!total_dependencies) {
420 return 1;
421 }
422
423 backward_load_order_size = total_dependencies * sizeof(dgraph_entry_t *);
424
425 backward_load_order = (dgraph_entry_t **)malloc(backward_load_order_size);
426 if (!backward_load_order) {
427 kload_log_error("malloc failure" KNL);
428 return 0;
429 }
430 bzero(backward_load_order, backward_load_order_size);
431
432 backward_load_order = fill_backward_load_order(backward_load_order,
433 &total_dependencies, dgraph->root, &list_index);
434 if (!backward_load_order) {
435 kload_log_error("error establishing load order" KNL);
436 return 0;
437 }
438
439 load_order_size = dgraph->length * sizeof(dgraph_entry_t *);
440 dgraph->load_order = (dgraph_entry_t **)malloc(load_order_size);
441 if (!dgraph->load_order) {
442 kload_log_error("malloc failure" KNL);
443 return 0;
444 }
445 bzero(dgraph->load_order, load_order_size);
446
447
448 /* Reverse the list into the dgraph's load_order list,
449 * removing any duplicates.
450 */
451 backward_index = list_index;
452 //
453 // the required 1 is taken off in loop below!
454
455 forward_index = 0;
456 do {
457 dgraph_entry_t * current_entry;
458 unsigned int already_got_it = 0;
459
460 backward_index--;
461
462 /* Get the entry to check.
463 */
464 current_entry = backward_load_order[backward_index];
465
466 /* Did we already get it?
467 */
468 for (list_index = 0; list_index < forward_index; list_index++) {
469 if (current_entry == dgraph->load_order[list_index]) {
470 already_got_it = 1;
471 break;
472 }
473 }
474
475 if (already_got_it) {
476 continue;
477 }
478
479 /* Haven't seen it before; tack it onto the load-order list.
480 */
481 dgraph->load_order[forward_index++] = current_entry;
482
483 } while (backward_index > 0);
484
485 free(backward_load_order);
486
487 return 1;
488 }
489
490 /*******************************************************************************
491 *
492 *******************************************************************************/
493 void dgraph_log(dgraph_t * depgraph)
494 {
495 unsigned int i, j;
496
497 kload_log_message("flattened dependency list: " KNL);
498 for (i = 0; i < depgraph->length; i++) {
499 dgraph_entry_t * current = depgraph->graph[i];
500
501 kload_log_message(" %s" KNL, current->name);
502 kload_log_message(" is kernel component: %s" KNL,
503 current->is_kernel_component ? "yes" : "no");
504 kload_log_message(" expected kmod name: [%s]" KNL,
505 current->expected_kmod_name);
506 kload_log_message(" expected kmod vers: [%s]" KNL,
507 current->expected_kmod_vers);
508 }
509 kload_log_message("" KNL);
510
511 kload_log_message("load order dependency list: " KNL);
512 for (i = 0; i < depgraph->length; i++) {
513 dgraph_entry_t * current = depgraph->load_order[i];
514 kload_log_message(" %s" KNL, current->name);
515 }
516 kload_log_message("" KNL);
517
518 kload_log_message("dependency graph: " KNL);
519 for (i = 0; i < depgraph->length; i++) {
520 dgraph_entry_t * current = depgraph->graph[i];
521 for (j = 0; j < current->num_dependencies; j++) {
522 dgraph_entry_t * cdep = current->dependencies[j];
523 kload_log_message(" %s -> %s" KNL, current->name, cdep->name);
524 }
525 }
526 kload_log_message("" KNL);
527
528 return;
529 }
530
531 /*******************************************************************************
532 *
533 *******************************************************************************/
534 dgraph_entry_t * dgraph_find_dependent(dgraph_t * dgraph, const char * name)
535 {
536 unsigned int i;
537
538 for (i = 0; i < dgraph->length; i++) {
539 dgraph_entry_t * current_entry = dgraph->graph[i];
540 if (0 == strcmp(name, current_entry->name)) {
541 return current_entry;
542 }
543 }
544
545 return NULL;
546 }
547
548 /*******************************************************************************
549 *
550 *******************************************************************************/
551 dgraph_entry_t * dgraph_add_dependent(
552 dgraph_t * dgraph,
553 const char * name,
554 #ifdef KERNEL
555 void * object,
556 size_t object_length,
557 bool object_is_kmem,
558 #endif /* KERNEL */
559 const char * expected_kmod_name,
560 const char * expected_kmod_vers,
561 vm_address_t load_address,
562 char is_kernel_component)
563 {
564 int error = 0;
565 dgraph_entry_t * found_entry = NULL;
566 dgraph_entry_t * new_entry = NULL; // free on error
567 dgraph_entry_t * the_entry = NULL; // returned
568
569 /* Already got it? Great!
570 */
571 found_entry = dgraph_find_dependent(dgraph, name);
572 if (found_entry) {
573 if (found_entry->is_kernel_component != is_kernel_component) {
574 kload_log_error(
575 "%s is already defined as a %skernel component" KNL,
576 name, found_entry->is_kernel_component ? "" : "non-");
577 error = 1;
578 goto finish;
579 }
580
581 if (load_address != 0) {
582 if (found_entry->loaded_address == 0) {
583 found_entry->do_load = 0;
584 found_entry->loaded_address = load_address;
585 } else if (found_entry->loaded_address != load_address) {
586 kload_log_error(
587 "%s has been assigned two different addresses (0x%x, 0x%x) KNL",
588 found_entry->name,
589 found_entry->loaded_address,
590 load_address);
591 error = 1;
592 goto finish;
593 }
594 }
595 the_entry = found_entry;
596 goto finish;
597 }
598
599 /* If the graph is full, make it bigger.
600 */
601 if (dgraph->length == dgraph->capacity) {
602 unsigned int old_capacity = dgraph->capacity;
603 dgraph_entry_t ** newgraph;
604
605 dgraph->capacity *= 2;
606 newgraph = (dgraph_entry_t **)malloc(dgraph->capacity *
607 sizeof(dgraph_entry_t *));
608 if (!newgraph) {
609 return NULL;
610 }
611 memcpy(newgraph, dgraph->graph, old_capacity * sizeof(dgraph_entry_t *));
612 free(dgraph->graph);
613 dgraph->graph = newgraph;
614 }
615
616 if (strlen(expected_kmod_name) > KMOD_MAX_NAME - 1) {
617 kload_log_error("expected kmod name \"%s\" is too long" KNL,
618 expected_kmod_name);
619 error = 1;
620 goto finish;
621 }
622
623 /* Fill it.
624 */
625 new_entry = (dgraph_entry_t *)malloc(sizeof(dgraph_entry_t));
626 if (!new_entry) {
627 error = 1;
628 goto finish;
629 }
630 bzero(new_entry, sizeof(dgraph_entry_t));
631 new_entry->expected_kmod_name = strdup(expected_kmod_name);
632 if (!new_entry->expected_kmod_name) {
633 error = 1;
634 goto finish;
635 }
636 new_entry->expected_kmod_vers = strdup(expected_kmod_vers);
637 if (!new_entry->expected_kmod_vers) {
638 error = 1;
639 goto finish;
640 }
641 new_entry->is_kernel_component = is_kernel_component;
642
643 // /hacks
644 new_entry->is_symbol_set = (2 & is_kernel_component);
645
646 new_entry->opaques = 0;
647 if (!strncmp(new_entry->expected_kmod_name,
648 "com.apple.kpi", strlen("com.apple.kpi")))
649 new_entry->opaques |= kOpaqueLink;
650 if (!strcmp(new_entry->expected_kmod_name,
651 "com.apple.kernel"))
652 new_entry->opaques |= kOpaqueLink | kRawKernelLink;
653 // hacks/
654
655 dgraph->has_symbol_sets |= new_entry->is_symbol_set;
656
657 new_entry->do_load = !is_kernel_component;
658
659 #ifndef KERNEL
660 new_entry->object = NULL; // provided elswehere in userland
661 new_entry->object_length = 0;
662 #else
663 new_entry->object = object;
664 new_entry->object_length = object_length;
665 new_entry->object_is_kmem = object_is_kmem;
666 #endif /* KERNEL */
667 new_entry->name = strdup(name);
668 if (!new_entry->name) {
669 error = 1;
670 goto finish;
671 }
672 dgraph->graph[dgraph->length++] = new_entry;
673
674
675 /* Create a dependency list for the entry. Start with 5 slots.
676 */
677 new_entry->dependencies_capacity = 5;
678 new_entry->num_dependencies = 0;
679 new_entry->dependencies = (dgraph_entry_t **)malloc(
680 new_entry->dependencies_capacity * sizeof(dgraph_entry_t *));
681 if (!new_entry->dependencies) {
682 error = 1;
683 goto finish;
684 }
685
686 if (new_entry->loaded_address == 0) {
687 new_entry->loaded_address = load_address;
688 if (load_address != 0) {
689 new_entry->do_load = 0;
690 }
691 }
692
693 the_entry = new_entry;
694
695 finish:
696 if (error) {
697 if (new_entry) __dgraph_entry_free(new_entry);
698 the_entry = new_entry = NULL;
699 }
700 return the_entry;
701 }
702
703 /*******************************************************************************
704 *
705 *******************************************************************************/
706 dgraph_entry_t * dgraph_add_dependency(
707 dgraph_t * dgraph,
708 dgraph_entry_t * current_dependent,
709 const char * name,
710 #ifdef KERNEL
711 void * object,
712 size_t object_length,
713 bool object_is_kmem,
714 #endif /* KERNEL */
715 const char * expected_kmod_name,
716 const char * expected_kmod_vers,
717 vm_address_t load_address,
718 char is_kernel_component)
719 {
720 dgraph_entry_t * dependency = NULL;
721 unsigned int i = 0;
722
723 /* If the dependent's dependency list is full, make it bigger.
724 */
725 if (current_dependent->num_dependencies ==
726 current_dependent->dependencies_capacity) {
727
728 unsigned int old_capacity = current_dependent->dependencies_capacity;
729 dgraph_entry_t ** newlist;
730
731 current_dependent->dependencies_capacity *= 2;
732 newlist = (dgraph_entry_t **)malloc(
733 (current_dependent->dependencies_capacity *
734 sizeof(dgraph_entry_t *)) );
735
736 if (!newlist) {
737 return NULL;
738 }
739 memcpy(newlist, current_dependent->dependencies,
740 old_capacity * sizeof(dgraph_entry_t *));
741 free(current_dependent->dependencies);
742 current_dependent->dependencies = newlist;
743 }
744
745
746 /* Find or add the entry for the new dependency.
747 */
748 dependency = dgraph_add_dependent(dgraph, name,
749 #ifdef KERNEL
750 object, object_length, object_is_kmem,
751 #endif /* KERNEL */
752 expected_kmod_name, expected_kmod_vers, load_address,
753 is_kernel_component);
754 if (!dependency) {
755 return NULL;
756 }
757
758 if (dependency == current_dependent) {
759 kload_log_error("attempt to set dependency on itself: %s" KNL,
760 current_dependent->name);
761 return NULL;
762 }
763
764 for (i = 0; i < current_dependent->num_dependencies; i++) {
765 dgraph_entry_t * this_dependency = current_dependent->dependencies[i];
766 if (this_dependency == dependency) {
767 return dependency;
768 }
769 }
770
771 /* Fill in the dependency.
772 */
773 current_dependent->dependencies[current_dependent->num_dependencies] =
774 dependency;
775 current_dependent->num_dependencies++;
776
777 current_dependent->opaque_link |= dependency->opaques;
778 dgraph->has_opaque_links |= current_dependent->opaque_link;
779
780 return dependency;
781 }