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