]> git.saurik.com Git - apple/system_cmds.git/blame - kmodload.tproj/kmodload.c
system_cmds-433.4.tar.gz
[apple/system_cmds.git] / kmodload.tproj / kmodload.c
CommitLineData
916eb79e
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*-
25 * Copyright (c) 1997 Doug Rabson
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * Original code from:
50 * "kldload.c,v 1.5 1998/07/06 06:58:32 charnier Exp"
51 */
52#ifndef lint
53static const char rcsid[] =
54 "$Id: kmodload.c,v 1.14 2002/04/15 20:28:30 lindak Exp $";
55#endif /* not lint */
56
57#include <stdlib.h>
58#include <err.h>
59#include <sys/file.h>
60#include <nlist.h>
61#include <stdio.h>
62#include <unistd.h>
63#include <sys/param.h>
64#include <sys/stat.h>
65#include <sys/mman.h>
66
67#include <paths.h>
68
69#include <mach/mach.h>
70#include <mach/mach_error.h>
71#include <mach/mach_host.h>
72#include <mach-o/kld.h>
73#include <mach-o/fat.h>
74
75#include <CoreFoundation/CoreFoundation.h>
76
77#include "kld_patch.h"
78#include "vers_rsrc.h"
79
80#define KMOD_ERROR_USAGE 1
81#define KMOD_ERROR_PERMS 2
82#define KMOD_ERROR_LOADING 3
83#define KMOD_ERROR_INTERNAL 4
84#define KMOD_ERROR_ALREADY 5
85
86#define kKMOD_INFO_SYMBOLNAME "_kmod_info"
87#define kKmodsymsName "kmodsyms"
88
89static mach_port_t kernel_port;
90static mach_port_t kernel_priv_port;
91
92static kmod_info_t *module_dependencies = 0;
93static vm_address_t kernel_alloc_address = 0;
94static unsigned long kernel_alloc_size = 0;
95static vm_address_t kernel_load_address = 0;
96static unsigned long kernel_load_size = 0;
97static unsigned long kernel_hdr_size = 0;
98static unsigned long kernel_hdr_pad = 0;
99static unsigned long faked_kernel_load_address = 0;
100
101static kmod_info_t *loaded_modules = 0;
102static int loaded_count = 0;
103
104static char *progname = "program name?";
105static int kmodsyms = 0;
106static int link_addrs_set = 0;
107static int verbose = 0;
108
109static char *debugdumpfile = NULL;
110
111// must not be static; kld library calls
112extern void kld_error_vprintf(const char *format, va_list ap);
113static void e_printf(const char *fmt, ...);
114static void v_printf(const char *fmt, ...);
115
116static void machwarn(int error, const char *message);
117static void macherr(int error, const char *message);
118
119static unsigned long linkedit_address(unsigned long size,
120 unsigned long headers_size);
121static void abort_load(int exitcode, const char *fmt, ...);
122static void map_and_patch(const char *base,
123 const char **library_paths,
124 const char *module);
125static void link_base(const char *base,
126 const char **dependency_paths,
127 const vm_address_t *dependency_addrs);
128static void clear_globals(void);
129static kmod_info_t *map_module(const char *filename);
130static struct mach_header *link_module(const char *filename,
131 const char *output);
132static vm_address_t update_kmod_info(struct mach_header *mach_header);
133static kmod_t load_module(struct mach_header *mach_header,
134 vm_address_t info);
135static void set_module_dependencies(kmod_t id);
136static void start_module(kmod_t id);
137
138static void
139usage(void)
140{
141 if (kmodsyms) {
142 fprintf(stderr, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] -o symbolfile modulefile\n", progname);
143 fprintf(stderr, " %s [-v] -k kernelfile [-d dependencyfile@address] -o symbolfile modulefile@address\n",
144 progname);
145 } else {
146 fprintf(stderr, "usage: %s [-v] [-k kernelfile] [-d dependencyfile] [-o symbolfile] modulefile\n", progname);
147 }
148 fflush(stderr);
149 exit(KMOD_ERROR_USAGE);
150}
151
152int
153main(int argc, char** argv)
154{
155 int c, r, i;
156 char * kernel = _PATH_UNIX;
157 int kernel_set = 0;
158 char * gdbfile = 0;
159#define MAX_DEPENDANCIES 128
160 char * dependencies[MAX_DEPENDANCIES];
161 vm_address_t loaded_addresses[MAX_DEPENDANCIES];
162 int dependency_count = 0;
163 struct mach_header *rld_header;
164
165 char * module_path = "";
166 vm_address_t module_info = 0;
167 vm_address_t module_faked_address = 0;
168 kmod_t module_id = 0;
169 kmod_info_t *file_kinfo;
170
171 if ((progname = strrchr(argv[0], '/')) == NULL)
172 progname = argv[0];
173 else
174 ++progname;
175
176 kmodsyms = !strcmp(progname, kKmodsymsName);
177
178 fprintf(stderr, "%s is deprecated; use kextload(8) instead\n", progname);
179 sleep(5);
180
181 // XXX things to add:
182 // -p data string to send as outofband data on start
183 // -P data file to send as outofband data on start
184
185 while ((c = getopt(argc, argv, "D:d:o:k:v")) != -1)
186 switch (c) {
187 case 'd':
188 dependencies[dependency_count] = optarg;
189 if (kmodsyms) {
190 char *address;
191 if ((address = strrchr(optarg, '@'))) {
192 *address++ = 0;
193 loaded_addresses[dependency_count] = strtoul(address, NULL, 0);
194 link_addrs_set++;
195 } else {
196 loaded_addresses[dependency_count] = 0;
197 }
198 }
199 if (++dependency_count == MAX_DEPENDANCIES) {
200 abort_load(KMOD_ERROR_INTERNAL,
201 "internal error, dependency count overflow.");
202 }
203 break;
204 case 'o':
205 gdbfile = optarg;
206 break;
207 case 'k':
208 kernel_set++;
209 kernel = optarg;
210 break;
211 case 'v':
212 verbose = 1;
213 break;
214 case 'D':
215 debugdumpfile = optarg;
216 break;
217 default:
218 usage();
219 }
220 argc -= optind;
221 argv += optind;
222
223 dependencies[dependency_count] = 0;
224 loaded_addresses[dependency_count] = 0;
225
226 if (argc != 1) usage();
227
228 module_path = argv[0];
229
230 if (kmodsyms) {
231 char *address;
232
233 if (!gdbfile) usage();
234
235 // check for @address
236 if ((address = strrchr(module_path, '@'))) {
237 *address++ = 0;
238 module_faked_address = strtoul(address, NULL, 0);
239 link_addrs_set++;
240 } else {
241 module_faked_address = 0;
242 }
243
244 // if any arg uses @address then they all must be and the kernel must be set
245 if (link_addrs_set) {
246 if (!kernel_set) usage();
247 if (!module_faked_address) usage();
248 for (i=0; i < dependency_count; i++) {
249 if (!loaded_addresses[i]) usage();
250 }
251 }
252 }
253
254 // map the module if possible, map_module will fail if there is a problem
255 file_kinfo = map_module(module_path);
256
257 if (!link_addrs_set) {
258 kmod_info_t *k;
259
260 // we only need the kernel port if we need to lookup loaded kmods
261 r = task_for_pid(mach_task_self(), 0, &kernel_port);
262 machwarn(r, "unable to get kernel task port");
263 if (KERN_SUCCESS != r) {
264 abort_load(KMOD_ERROR_PERMS,
265 "You must be running as root to load modules in the kernel.");
266 }
267
268 //get loaded modules
269 r = kmod_get_info(kernel_port, (void *)&loaded_modules, &loaded_count); // never freed
270 macherr(r, "kmod_get_info() failed");
271
272 // check to see if the module has been loaded
273 k = loaded_modules;
274 while (k) {
275 if (!strcmp(k->name, file_kinfo->name)) {
276 if (!kmodsyms) {
277 abort_load(KMOD_ERROR_ALREADY,
278 "the module named '%s' is already loaded.", k->name);
279 } else {
280 module_faked_address = k->address;
281 }
282 break;
283 }
284 k = (k->next) ? (k + 1) : 0;
285 }
286
287 if (kmodsyms && !module_faked_address) {
288 abort_load(KMOD_ERROR_USAGE,
289 "the module named '%s' has not been loaded.", file_kinfo->name);
290 }
291
292 //XXX it would be nice to be able to verify this is the correct kernel
293 //XXX by comparing the kernel version strings (once we have them)
294 }
295
296 map_and_patch(kernel, dependencies, module_path);
297
298 // Tell the kld linker where to get its load address from
299 kld_address_func(linkedit_address);
300
301 // link the kernel along with any dependencies
302 link_base(kernel, dependencies, loaded_addresses);
303
304 if (kmodsyms) {
305 faked_kernel_load_address = module_faked_address;
306
307 if (!faked_kernel_load_address) {
308 abort_load(KMOD_ERROR_INTERNAL,
309 "internal error, fell thru without setting module load address.");
310 }
311 }
312
313 rld_header = link_module(module_path, gdbfile);
314 module_info = update_kmod_info(rld_header);
315
316 if (debugdumpfile)
317 kld_file_debug_dump(module_path, debugdumpfile);
318
319 if (kmodsyms) return 0;
320
321 // we need the priv port to load modules into the kernel
322 kernel_priv_port = mach_host_self(); /* if we are privileged */
323
324 module_id = load_module(rld_header, module_info);
325 set_module_dependencies(module_id);
326 start_module(module_id);
327
328 return 0;
329}
330
331static void
332machwarn(int error, const char *message)
333{
334 if (KERN_SUCCESS != error)
335 e_printf("%s: %s", message, mach_error_string(error));
336}
337
338static void
339macherr(int error, const char *message)
340{
341 if (KERN_SUCCESS != error)
342 abort_load(KMOD_ERROR_INTERNAL,
343 "%s: %s", message, mach_error_string(error));
344}
345
346static kmod_info_t *map_module(const char *filename)
347{
348 kmod_info_t *file_kinfo;
349
350 if (!kld_file_map(filename))
351 exit(KMOD_ERROR_LOADING);
352
353 file_kinfo = kld_file_lookupsymbol(filename, kKMOD_INFO_SYMBOLNAME);
354 if (!file_kinfo) {
355 abort_load(KMOD_ERROR_USAGE,
356 "%s is not a valid kernel module.", filename);
357 }
358
359 return file_kinfo;
360}
361
362static void
363map_and_patch(const char *base, const char **library_paths, const char *module)
364{
365 if (!kld_file_map(base))
366 exit(KMOD_ERROR_INTERNAL);
367 if (!kld_file_merge_OSObjects(base))
368 abort_load(KMOD_ERROR_LOADING, NULL);
369
370 if (*library_paths) {
371 char **library;
372 for (library = library_paths; *library; library++) {
373 map_module(*library);
374 if (!kld_file_patch_OSObjects(*library))
375 abort_load(KMOD_ERROR_LOADING, NULL);
376 }
377 }
378
379 // Patch the vtables of the object module we are about to load
380 // The module has already been mapped in the main() routine as part
381 // of validation
382 if (!kld_file_patch_OSObjects(module))
383 abort_load(KMOD_ERROR_LOADING, NULL);
384
385 // During the patch up process the mapped images were modified
386 // to avoid having to allocate more data than necessary.
387 // Now we have to give the patcher a chance to clean up after itself.
388 if (!kld_file_prepare_for_link())
389 abort_load(KMOD_ERROR_LOADING, NULL);
390}
391
392static void
393link_base(const char *base,
394 const char **dependency_paths,
395 const vm_address_t *dependency_addrs)
396{
397 struct mach_header *rld_header;
398 char *base_addr;
399 long base_size;
400 int ok;
401
402 // Get the address and size of the base, usually the kernel
403 base_addr = kld_file_getaddr(base, &base_size);
404 if (!base_addr)
405 exit(KMOD_ERROR_INTERNAL); // Error reported by kld library.
406
407 ok = kld_load_basefile_from_memory(base, base_addr, base_size);
408 fflush(stdout);
409 if (!ok)
410 abort_load(KMOD_ERROR_LOADING, "kld_load_basefile(%s) failed.", base);
411
412 if (*dependency_paths) {
413 char **dependency = dependency_paths;
414 const vm_address_t *load_addr = dependency_addrs;
415
416 while (*dependency) {
417 kmod_info_t *file_kinfo;
418
419 // Find the kmod_info structure in the image.
420 file_kinfo =
421 kld_file_lookupsymbol(*dependency, kKMOD_INFO_SYMBOLNAME);
422 if (!file_kinfo) {
423 abort_load(KMOD_ERROR_USAGE,
424 "%s is not a valid kernel module.", *dependency);
425 }
426
427 // find the address that this dependency is loaded at
428 if (kmodsyms && *load_addr) {
429 faked_kernel_load_address = *load_addr;
430 } else {
431 kmod_info_t *k;
432 kmod_info_t *tmp;
433 int found_it = 0;
434
435 // match up file version of kmod_info with kernel version
436 k = loaded_modules;
437 while (k) {
438 if (!strcmp(k->name, file_kinfo->name)) {
439 UInt32 kernel_kmod_version;
440 UInt32 file_kmod_version;
441
442 if (!VERS_parse_string(k->version, &kernel_kmod_version)) {
443 e_printf("can't parse version string \"%s\" in kernel kmod",
444 k->version);
445 abort_load(KMOD_ERROR_LOADING,
446 "can't parse kernel kmod version string \"%s\"", k->version);
447 }
448
449 if (!VERS_parse_string(file_kinfo->version, & file_kmod_version)) {
450 e_printf("can't parse version string \"%s\" in kmod file %s",
451 file_kinfo->version, *dependency);
452 abort_load(KMOD_ERROR_LOADING,
453 "can't parse version string \"%s\" in kmod file %s",
454 file_kinfo->version, *dependency);
455 }
456
457 if (kernel_kmod_version != file_kmod_version) {
458 e_printf("loaded kernel module '%s' version differs.", *dependency);
459 abort_load(KMOD_ERROR_LOADING,
460 "loaded version '%s', file version '%s'.",
461 k->version, file_kinfo->version);
462 }
463 found_it++;
464 break;
465 }
466 k = (k->next) ? (k + 1) : 0;
467 }
468 if (!found_it) {
469 abort_load(KMOD_ERROR_USAGE,
470 "kernel module '%s' is not loaded.", *dependency);
471 }
472
473 tmp = malloc(sizeof(kmod_info_t));
474 if (!tmp)
475 abort_load(KMOD_ERROR_LOADING, "no memory.");
476
477 *tmp = *k;
478 tmp->next = module_dependencies;
479 module_dependencies = tmp;
480
481 faked_kernel_load_address = k->address;
482 }
483
484 rld_header = link_module(*dependency, 0);
485
486 (void) update_kmod_info(rld_header);
487
488 dependency++; load_addr++;
489 }
490 /* make sure we clear these so clean up does the right thing. */
491 clear_globals();
492 }
493}
494
495#if !defined(page_round)
496#define page_trunc(p) ((int)(p)&~(vm_page_size-1))
497#define page_round(p) page_trunc((int)(p)+vm_page_size-1)
498#endif
499
500static unsigned long
501linkedit_address(unsigned long size, unsigned long headers_size)
502{
503 int r;
504 unsigned long round_segments_size;
505 unsigned long round_headers_size;
506 unsigned long round_size;
507
508 kernel_load_size = size; // The actual size allocated by kld_load...
509
510 round_headers_size = page_round(headers_size);
511 round_segments_size = page_round(size - headers_size);
512 round_size = round_headers_size + round_segments_size;
513
514 kernel_alloc_size = round_size;
515 kernel_hdr_size = headers_size; // will need to be rounded to page *after* link.
516 kernel_hdr_pad = round_headers_size - headers_size;
517
518 if (faked_kernel_load_address) {
519 kernel_load_address = faked_kernel_load_address + kernel_hdr_pad;
520 v_printf("Returning fake load address of 0x%8x", kernel_load_address);
521 return kernel_load_address;
522 }
523 if (kmodsyms) {
524 abort_load(KMOD_ERROR_INTERNAL,
525 "internal error, almost tried to alloc kernel memory.");
526 }
527
528 r = vm_allocate(kernel_port, &kernel_alloc_address,
529 kernel_alloc_size, TRUE);
530 macherr(r, "unable to allocate kernel memory");
531
532 v_printf("allocated %ld bytes in kernel space at 0x%8x",
533 kernel_alloc_size, kernel_alloc_address);
534
535 kernel_load_address = kernel_alloc_address + kernel_hdr_pad;
536
537 v_printf("Returning load address of 0x%x", kernel_load_address);
538
539 return kernel_load_address;
540}
541
542static void
543clear_globals(void)
544{
545 faked_kernel_load_address = 0;
546 kernel_alloc_address = 0;
547 kernel_alloc_size = 0;
548 kernel_load_address = 0;
549 kernel_load_size = 0;
550 kernel_hdr_size = 0;
551 kernel_hdr_pad = 0;
552 return;
553}
554
555static struct mach_header *
556link_module(const char *filename, const char *output)
557{
558 struct mach_header *rld_header;
559 char *object_addr;
560 long object_size;
561 int ok;
562
563 // Get the address of the thined MachO image.
564 object_addr = kld_file_getaddr(filename, &object_size);
565 if (!object_addr)
566 abort_load(KMOD_ERROR_LOADING, NULL);
567
568 ok = kld_load_from_memory(&rld_header, filename,
569 object_addr, object_size, output);
570 fflush(stdout);
571 if (!ok)
572 abort_load(KMOD_ERROR_LOADING, "kld_load() failed.");
573
574 return rld_header;
575}
576
577// Update the kmod_info_t structure in the image to be laoded
578// Side effect of removing the kKMOD_INFO_SYMBOLNAME from the
579// loaded symbol name space, otherwise we would have a duplicate
580// defined symbol failure
581vm_address_t
582update_kmod_info(struct mach_header *mach_header)
583{
584 char * symbol = kKMOD_INFO_SYMBOLNAME;
585 kmod_info_t *info;
586 unsigned long value;
587 int ok;
588
589 ok = kld_lookup(symbol, &value); fflush(stdout);
590 if (!ok)
591 abort_load(KMOD_ERROR_LOADING, "kld_lookup(%s) failed.", symbol);
592
593 ok = kld_forget_symbol(symbol); fflush(stdout);
594 if (!ok)
595 abort_load(KMOD_ERROR_LOADING, "kld_forget_symbol(%s) failed.", symbol);
596
597 /* Get the kmod info by translating from the kernel address at value.
598 */
599 info = (kmod_info_t *)(value - (unsigned long)kernel_load_address + (unsigned long)mach_header);
600 v_printf("kmod name: %s", info->name);
601 v_printf("kmod start @ 0x%x", (vm_address_t)info->start);
602 v_printf("kmod stop @ 0x%x", (vm_address_t)info->stop);
603
604 /* Record link info in kmod info struct, rounding the hdr_size to fit
605 * the adjustment that was made.
606 */
607 info->address = kernel_alloc_address;
608 info->size = kernel_alloc_size;
609 info->hdr_size = page_round(kernel_hdr_size);
610
611 if (!info->start)
612 abort_load(KMOD_ERROR_LOADING, "invalid start address?");
613 else if (!info->stop)
614 abort_load(KMOD_ERROR_LOADING, "invalid stop address?");
615
616 return (vm_address_t)value;
617}
618
619static kmod_t
620load_module(struct mach_header *mach_header, vm_address_t info)
621{
622 int r;
623 kmod_t id;
624 vm_address_t vm_buffer = 0;
625
626 r = vm_allocate(mach_task_self(), &vm_buffer,
627 kernel_alloc_size, TRUE);
628 macherr(r, "unable to vm_allocate() copy buffer");
629
630 /* Copy the linked segment data into the page-aligned buffer.
631 * Do not round the header size here.
632 */
633 bzero((void *)vm_buffer, kernel_alloc_size);
634 memcpy((void *)vm_buffer, mach_header, kernel_hdr_size);
635 memcpy((void *)vm_buffer + page_round(kernel_hdr_size),
636 (void *)((unsigned long)mach_header + kernel_hdr_size),
637 kernel_load_size - kernel_hdr_size);
638
639 // copy linked header into kernel address space
640 r = vm_write(kernel_port, kernel_alloc_address,
641 vm_buffer, kernel_alloc_size);
642 macherr(r, "unable to write module into kernel memory");
643
644 // let the kernel know about it
645 r = kmod_create(kernel_priv_port, info, &id);
646 macherr(r, "unable to register module with kernel");
647
648 v_printf("kmod id %d successfully created at 0x%x size %ld.\n",
649 id, kernel_alloc_address, kernel_alloc_size);
650
651 // FIXME: make sure this happens even on failure
652
653 vm_deallocate(mach_task_self(), vm_buffer, kernel_alloc_size);
654 return id;
655}
656
657static void
658set_module_dependencies(kmod_t id)
659{
660 int r;
661 void * args = 0;
662 int argsCount= 0;
663 kmod_info_t *module = module_dependencies;
664
665 while (module) {
666
667 r = kmod_control(kernel_priv_port, KMOD_PACK_IDS(id, module->id), KMOD_CNTL_RETAIN, &args, &argsCount);
668 machwarn(r, "kmod_control(retain) failed");
669 if (r) {
670 clear_globals();
671 r = kmod_destroy(kernel_priv_port, id);
672 macherr(r, "kmod_destroy failed");
673 }
674
675 v_printf("kmod id %d reference count was sucessfully incremented.", module->id);
676
677 module = module->next;
678 }
679}
680
681static void
682start_module(kmod_t id)
683{
684 int r;
685 void * args = 0;
686 int argsCount= 0;
687
688 r = kmod_control(kernel_priv_port, id, KMOD_CNTL_START, &args, &argsCount);
689 machwarn(r, "kmod_control(start) failed");
690 if (r) {
691 clear_globals();
692 kmod_destroy(kernel_priv_port, id);
693 macherr(r, "kmod_destroy failed");
694 }
695
696 v_printf("kmod id %d successfully started.", id);
697}
698
699static void e_printf(const char *fmt, ...)
700{
701 va_list ap;
702 char msg[1024];
703
704 va_start(ap, fmt);
705 vsnprintf(msg, sizeof(msg), fmt, ap);
706 va_end(ap);
707
708 fprintf(stderr, "%s: %s\n", progname, msg);
709}
710
711static void v_printf(const char *fmt, ...)
712{
713 va_list ap;
714 char msg[1024];
715
716 if (!verbose) return;
717
718 va_start(ap, fmt);
719 vsnprintf(msg, sizeof(msg), fmt, ap);
720 va_end(ap);
721
722 printf("%s: %s\n", progname, msg);
723}
724
725static void abort_load(int exitcode, const char *fmt, ...)
726{
727 if (fmt) {
728 va_list ap;
729 char msg[1024];
730
731 va_start(ap, fmt);
732 vsnprintf(msg, sizeof(msg), fmt, ap);
733 va_end(ap);
734
735 fprintf(stderr, "%s: %s\n", progname, msg);
736 }
737
738 if (!faked_kernel_load_address
739 && (kernel_alloc_address || kernel_alloc_size)) {
740 int r;
741
742 v_printf("freeing %ld bytes in kernel space at 0x%x",
743 kernel_alloc_size, kernel_alloc_address);
744 r = vm_deallocate(kernel_port, kernel_alloc_address, kernel_alloc_size);
745 machwarn(r, "unable to cleanup kernel memory");
746 }
747
748 exit(exitcode);
749}
750
751__private_extern__ void
752kld_error_vprintf(const char *fmt, va_list ap)
753{
754 vfprintf(stderr, fmt, ap);
755 fflush(stderr);
756}