/*
 * Get the linkmap from the dynlinker.  Try to load kernel modules
 * from all objects in the linkmap.
 */
void
rumpuser_dl_bootstrap(rump_modinit_fn domodinit,
	rump_symload_fn symload, rump_compload_fn compload)
{
	struct link_map *map, *origmap, *mainmap;
	void *mainhandle;
	int error;

	mainhandle = dlopen(NULL, RTLD_NOW);
	if (dlinfo(mainhandle, RTLD_DI_LINKMAP, &mainmap) == -1) {
		fprintf(stderr, "warning: rumpuser module bootstrap "
		    "failed: %s\n", dlerror());
		return;
	}
	origmap = mainmap;

	/*
	 * Process last->first because that's the most probable
	 * order for dependencies
	 */
	for (; origmap->l_next; origmap = origmap->l_next)
		continue;

	/*
	 * Build symbol table to hand to the rump kernel.  Do this by
	 * iterating over all rump libraries and collecting symbol
	 * addresses and relocation info.
	 */
	error = 0;
	for (map = origmap; map && !error; map = map->l_prev) {
		if (strstr(map->l_name, "librump") != NULL || map == mainmap)
			error = getsymbols(map, map == mainmap);
	}

	if (error == 0) {
		void *trimmedsym, *trimmedstr;

		/*
		 * Allocate optimum-sized memory for storing tables
		 * and feed to kernel.  If memory allocation fails,
		 * just give the ones with extra context (although
		 * I'm pretty sure we'll die moments later due to
		 * memory running out).
		 */
		if ((trimmedsym = malloc(symtaboff)) != NULL) {
			memcpy(trimmedsym, symtab, symtaboff);
		} else {
			trimmedsym = symtab;
			symtab = NULL;
		}
		if ((trimmedstr = malloc(strtaboff)) != NULL) {
			memcpy(trimmedstr, strtab, strtaboff);
		} else {
			trimmedstr = strtab;
			strtab = NULL;
		}
		symload(trimmedsym, symtaboff, trimmedstr, strtaboff);
	}
	free(symtab);
	free(strtab);

	/*
	 * Next, load modules and components.
	 *
	 * Simply loop through all objects, ones unrelated to rump kernels
	 * will not contain link_set_rump_components (well, not including
	 * "sabotage", but that needs to be solved at another level anyway).
	 */
	for (map = origmap; map; map = map->l_prev) {
		void *handle;

		if (map == mainmap) {
			handle = mainhandle;
		} else {
			handle = dlopen(map->l_name, RTLD_LAZY);
			if (handle == NULL)
				continue;
		}
		process_object(handle, domodinit, compload);
		if (map != mainmap)
			dlclose(handle);
	}
}
Ejemplo n.º 2
0
/*
 * Get the linkmap from the dynlinker.  Try to load kernel modules
 * from all objects in the linkmap.
 */
void
rumpuser_dl_bootstrap(rump_modinit_fn domodinit,
	rump_symload_fn symload, rump_compload_fn compload)
{
	struct link_map *map, *origmap, *mainmap;
	void *mainhandle;
	int error;

	mainhandle = dlopen(NULL, RTLD_NOW);
	/* Will be null if statically linked so just return */
	if (mainhandle == NULL)
		return;
	if (dlinfo(mainhandle, RTLD_DI_LINKMAP, &mainmap) == -1) {
		fprintf(stderr, "warning: rumpuser module bootstrap "
		    "failed: %s\n", dlerror());
		return;
	}
	origmap = mainmap;

	/*
	 * Use a heuristic to determine if we are static linked.
	 * A dynamically linked binary should always have at least
	 * two objects: itself and ld.so.
	 *
	 * In a statically linked binary with glibc the linkmap
	 * contains some "info" that leads to a segfault.  Since we
	 * can't really do anything useful in here without ld.so, just
	 * simply bail and let the symbol references in librump do the
	 * right things.
	 */
	if (origmap->l_next == NULL && origmap->l_prev == NULL) {
		dlclose(mainhandle);
		return;
	}

	/*
	 * Process last->first because that's the most probable
	 * order for dependencies
	 */
	for (; origmap->l_next; origmap = origmap->l_next)
		continue;

	/*
	 * Build symbol table to hand to the rump kernel.  Do this by
	 * iterating over all rump libraries and collecting symbol
	 * addresses and relocation info.
	 */
	error = 0;
	for (map = origmap; map && !error; map = map->l_prev) {
		if (strstr(map->l_name, "librump") != NULL || map == mainmap)
			error = getsymbols(map, map == mainmap);
	}

	if (error == 0) {
		void *trimmedsym, *trimmedstr;

		/*
		 * Allocate optimum-sized memory for storing tables
		 * and feed to kernel.  If memory allocation fails,
		 * just give the ones with extra context (although
		 * I'm pretty sure we'll die moments later due to
		 * memory running out).
		 */
		if ((trimmedsym = malloc(symtaboff)) != NULL) {
			memcpy(trimmedsym, symtab, symtaboff);
		} else {
			trimmedsym = symtab;
			symtab = NULL;
		}
		if ((trimmedstr = malloc(strtaboff)) != NULL) {
			memcpy(trimmedstr, strtab, strtaboff);
		} else {
			trimmedstr = strtab;
			strtab = NULL;
		}
		symload(trimmedsym, symtaboff, trimmedstr, strtaboff);
	}
	free(symtab);
	free(strtab);

	/*
	 * Next, load modules and components.
	 *
	 * Simply loop through all objects, ones unrelated to rump kernels
	 * will not contain link_set_rump_components (well, not including
	 * "sabotage", but that needs to be solved at another level anyway).
	 */
	for (map = origmap; map; map = map->l_prev) {
		void *handle;

		if (map == mainmap) {
			handle = mainhandle;
		} else {
			handle = dlopen(map->l_name, RTLD_LAZY);
			if (handle == NULL)
				continue;
		}
		process_object(handle, domodinit, compload);
		if (map != mainmap)
			dlclose(handle);
	}
}