Example #1
1
/*
 * Insert an additional listener in to the sorted list of listeners
 */
void
add_listener(struct Listener_head *listeners, struct Listener *listener) {
    assert(listeners != NULL);
    assert(listener != NULL);
    assert(listener->address != NULL);
    listener_ref_get(listener);

    if (SLIST_FIRST(listeners) == NULL ||
            address_compare(listener->address, SLIST_FIRST(listeners)->address) < 0) {
        SLIST_INSERT_HEAD(listeners, listener, entries);
        return;
    }

    struct Listener *iter;
    SLIST_FOREACH(iter, listeners, entries) {
        if (SLIST_NEXT(iter, entries) == NULL ||
                address_compare(listener->address, SLIST_NEXT(iter, entries)->address) < 0) {
            SLIST_INSERT_AFTER(iter, listener, entries);
            return;
        }
    }
}
Example #2
0
void
ngram(const char *word, size_t len, size_t gramsize)
{
	char		*c = 0;
	size_t		 i = 0;
	struct gram	*prevgram = NULL;

	SLIST_INIT(&grams_head);

	c = (char *) word;

	while (iscntrl(*c) == 0) {
		struct gram	*newgram = init_gram(gramsize);

		i = 0;

		while (i < gramsize && iscntrl(*c) == 0)
			newgram ->buf[++i] = *c++;
		newgram->buf[i] = '\0';

		if (prevgram == NULL)
			SLIST_INSERT_HEAD(&grams_head, newgram, grams);
		else
			SLIST_INSERT_AFTER(prevgram, newgram, grams);
		prevgram = newgram;
	}
}
Example #3
0
/* Read and parse a configuration file */
void
read_config(const char *filename)
{
	char buf[5000], plugin_name[50], plugin_path[100];
	char plugin_data_name[100];
	FILE *f, *fs;
	char *p;
	int line = 0;
	void *handle;
	enum sections {
		Servers, Options, Plugin
	} section = Servers;
	struct plugins_data *plugins_data;
	struct plugin_options *popt, *last_popt = NULL;

	if ((f = fopen(filename, "r")) == NULL)
		errx(1, "Can't open: %s", filename);
	while (fgets(buf, sizeof(buf), f) != NULL) {
		line++;
		/* Ignore empty lines and comments */
		if (buf[0] == '\n' || buf[0] == '#')
			continue;

		/* strip \n */
		if ((p = strchr(buf, '\n')) != NULL)
			*p = '\0';

		/* A new section starts */
		if (buf[0] == '[') {
			p = strchr(buf, ']');
			if (p == NULL || *(p + 1) != '\0')
				errx(1, "Config file syntax error. Line: %d", line);
			*p = '\0';
			if (strcasecmp(buf + 1, "servers") == 0) {
				section = Servers;
				continue;
			}
			if (strcasecmp(buf + 1, "options") == 0) {
				section = Options;
				continue;
			}
			if ((p = strcasestr(buf, "-plugin")) != NULL) {
				if (plugins_number > MAX_PLUGINS - 1)
					errx(1, "Too many plugins. Line: %d", line);

				section = Plugin;
				*p = '\0';
				strlcpy(plugin_name, buf + 1, sizeof(plugin_name));

				strlcpy(plugin_data_name, plugin_name, sizeof(plugin_data_name));
				strlcat(plugin_data_name, "_plugin", sizeof(plugin_data_name));

				strlcpy(plugin_path, plugin_base, sizeof(plugin_path));
				strlcat(plugin_path, "dhcprelya_", sizeof(plugin_path));
				strlcat(plugin_path, plugin_name, sizeof(plugin_path));
				strlcat(plugin_path, "_plugin.so", sizeof(plugin_path));
				handle = dlopen(plugin_path, RTLD_LAZY);
				if (handle == NULL) {
					printf("dlerror(): %s\n", dlerror());
					errx(1, "Can't open plugin: %s", plugin_path);
				}
				plugins_data = dlsym(handle, plugin_data_name);
				if (plugins_data == NULL)
					errx(1, "Can't load symbol %s", plugin_data_name);
				plugins[plugins_number] = malloc(sizeof(struct plugin_data));
				if (plugins[plugins_number] == NULL)
					process_error(EX_MEM, "malloc");

				memcpy(plugins[plugins_number], plugins_data, sizeof(struct plugin_data));

				/* head for options list for this plugin */
				options_heads[plugins_number] = malloc(sizeof(plugin_options_head_t));
				if (options_heads[plugins_number] == NULL)
					process_error(EX_MEM, "malloc");
				SLIST_INIT(options_heads[plugins_number]);

				plugins_number++;

				logd(LOG_DEBUG, "Plugin #%d (%s) loaded", plugins_number, plugin_name);
				continue;
			}
			errx(1, "Section name error. Line: %d", line);
		}
		if (section == Servers) {
			if ((p = strchr(buf, '=')) == NULL)
				parse_servers_line(buf);
			else {
				*p = '\0';
				p++;
				if (strcasecmp(buf, "file") != 0)
					errx(1, "Unknown option in Server section. Line: %d", line);
				if ((fs = fopen(p, "r")) == NULL)
					errx(1, "Can't open servers config file: %s", p);
				while (fgets(buf, sizeof(buf), fs) != NULL) {
					/* Ignore empty lines and comments */
					if (buf[0] == '\n' || buf[0] == '#')
						continue;

					/* strip \n */
					if ((p = strchr(buf, '\n')) != NULL)
						*p = '\0';

					parse_servers_line(buf);
				}
				fclose(fs);
			}
		}
		if (section == Options) {
			p = strchr(buf, '=');
			if (p == NULL)
				errx(1, "Option error. Line: %d", line);
			*p = '\0';
			p++;

			if (strcasecmp(buf, "max_packet_size") == 0) {
				max_packet_size = strtol(p, NULL, 10);
				if (max_packet_size < 300 || max_packet_size > DHCP_MTU_MAX)
					errx(1, "Wrong packet size. Line: %d", line);
				logd(LOG_DEBUG, "Option max_packet_size set to: %d", max_packet_size);
				continue;
			}
			if (strcasecmp(buf, "max_hops") == 0) {
				max_hops = strtol(p, NULL, 10);
				if (max_hops < 1 || max_hops > 16)
					errx(1, "Wrong hops number. Line: %d", line);
				logd(LOG_DEBUG, "Option max_hops set to: %d", max_hops);
				continue;
			}
			if (strcasecmp(buf, "rps_limit") == 0) {
				errno = 0;
				rps_limit = strtol(p, NULL, 10);
				if (errno != 0)
					errx(1, "rps_limit number error");
				logd(LOG_DEBUG, "Option rps_limit set to: %d", rps_limit);
				continue;
			}
			if (strcasecmp(buf, "plugin_path") == 0) {
				strlcpy(plugin_base, p, sizeof(plugin_base));
				if (plugin_base[strlen(plugin_base) - 1] != '/')
					strlcat(plugin_base, "/", sizeof(plugin_base));
				logd(LOG_DEBUG, "Option plugin_base set to: %s", plugin_base);
				continue;
			}
			errx(1, "Unknown option. Line: %d", line);
		}
		if (section == Plugin) {
			popt = malloc(sizeof(struct plugin_options));
			if (popt == NULL)
				process_error(EX_MEM, "malloc");
			popt->option_line = malloc(strlen(buf) + 1);
			if (popt->option_line == NULL)
				process_error(EX_MEM, "malloc");
			strcpy(popt->option_line, buf);
			if (SLIST_EMPTY(options_heads[plugins_number - 1])) {
				SLIST_INSERT_HEAD(options_heads[plugins_number - 1], popt, next);
				last_popt = popt;
			} else {
				SLIST_INSERT_AFTER(last_popt, popt, next);
				last_popt = popt;
			}
		}
	}
	fclose(f);
	if (if_num == 0)
		errx(1, "No interfaces found to listen. Exiting.");
}
void
symtable_dump(FILE *ofile)
{
	/*
	 * Sort the registers by address with a simple insertion sort.
	 * Put bitmasks next to the first register that defines them.
	 * Put constants at the end.
	 */
	symlist_t registers;
	symlist_t masks;
	symlist_t constants;
	symlist_t download_constants;
	symlist_t aliases;
	symlist_t exported_labels;
	u_int	  i;

	SLIST_INIT(&registers);
	SLIST_INIT(&masks);
	SLIST_INIT(&constants);
	SLIST_INIT(&download_constants);
	SLIST_INIT(&aliases);
	SLIST_INIT(&exported_labels);

	if (symtable != NULL) {
		DBT	 key;
		DBT	 data;
		int	 flag = R_FIRST;

		while (symtable->seq(symtable, &key, &data, flag) == 0) {
			symbol_t *cursym;

			memcpy(&cursym, data.data, sizeof(cursym));
			switch(cursym->type) {
			case REGISTER:
			case SCBLOC:
			case SRAMLOC:
				symlist_add(&registers, cursym, SYMLIST_SORT);
				break;
			case MASK:
			case BIT:
				symlist_add(&masks, cursym, SYMLIST_SORT);
				break;
			case CONST:
				symlist_add(&constants, cursym,
					    SYMLIST_INSERT_HEAD);
				break;
			case DOWNLOAD_CONST:
				symlist_add(&download_constants, cursym,
					    SYMLIST_INSERT_HEAD);
				break;
			case ALIAS:
				symlist_add(&aliases, cursym,
					    SYMLIST_INSERT_HEAD);
				break;
			case LABEL:
				if (cursym->info.linfo->exported == 0)
					break;
				symlist_add(&exported_labels, cursym,
					    SYMLIST_INSERT_HEAD);
				break;
			default:
				break;
			}
			flag = R_NEXT;
		}

		/* Put in the masks and bits */
		while (SLIST_FIRST(&masks) != NULL) {
			symbol_node_t *curnode;
			symbol_node_t *regnode;
			char *regname;

			curnode = SLIST_FIRST(&masks);
			SLIST_REMOVE_HEAD(&masks, links);

			regnode =
			    SLIST_FIRST(&curnode->symbol->info.minfo->symrefs);
			regname = regnode->symbol->name;
			regnode = symlist_search(&registers, regname);
			SLIST_INSERT_AFTER(regnode, curnode, links);
		}

		/* Add the aliases */
		while (SLIST_FIRST(&aliases) != NULL) {
			symbol_node_t *curnode;
			symbol_node_t *regnode;
			char *regname;

			curnode = SLIST_FIRST(&aliases);
			SLIST_REMOVE_HEAD(&aliases, links);

			regname = curnode->symbol->info.ainfo->parent->name;
			regnode = symlist_search(&registers, regname);
			SLIST_INSERT_AFTER(regnode, curnode, links);
		}

		/* Output what we have */
		fprintf(ofile,
"/*
 * DO NOT EDIT - This file is automatically generated
 *		 from the following source files:
 *
%s */\n", versions);
		while (SLIST_FIRST(&registers) != NULL) {
			symbol_node_t *curnode;
			u_int value;
			char *tab_str;
			char *tab_str2;

			curnode = SLIST_FIRST(&registers);
			SLIST_REMOVE_HEAD(&registers, links);
			switch(curnode->symbol->type) {
			case REGISTER:
			case SCBLOC:
			case SRAMLOC:
				fprintf(ofile, "\n");
				value = curnode->symbol->info.rinfo->address;
				tab_str = "\t";
				tab_str2 = "\t\t";
				break;
			case ALIAS:
			{
				symbol_t *parent;

				parent = curnode->symbol->info.ainfo->parent;
				value = parent->info.rinfo->address;
				tab_str = "\t";
				tab_str2 = "\t\t";
				break;
			}
			case MASK:
			case BIT:
				value = curnode->symbol->info.minfo->mask;
				tab_str = "\t\t";
				tab_str2 = "\t";
				break;
			default:
				value = 0; /* Quiet compiler */
				tab_str = NULL;
				tab_str2 = NULL;
				stop("symtable_dump: Invalid symbol type "
				     "encountered", EX_SOFTWARE);
				break;
			}
			fprintf(ofile, "#define%s%-16s%s0x%02x\n",
				tab_str, curnode->symbol->name, tab_str2,
				value);
			free(curnode);
		}
		fprintf(ofile, "\n\n");

		while (SLIST_FIRST(&constants) != NULL) {
			symbol_node_t *curnode;

			curnode = SLIST_FIRST(&constants);
			SLIST_REMOVE_HEAD(&constants, links);
			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
				curnode->symbol->name,
				curnode->symbol->info.cinfo->value);
			free(curnode);
		}

		
		fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");

		for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {
			symbol_node_t *curnode;

			curnode = SLIST_FIRST(&download_constants);
			SLIST_REMOVE_HEAD(&download_constants, links);
			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
				curnode->symbol->name,
				curnode->symbol->info.cinfo->value);
			free(curnode);
		}
		fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);

		fprintf(ofile, "\n\n/* Exported Labels */\n");

		while (SLIST_FIRST(&exported_labels) != NULL) {
			symbol_node_t *curnode;

			curnode = SLIST_FIRST(&exported_labels);
			SLIST_REMOVE_HEAD(&exported_labels, links);
			fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",
				curnode->symbol->name,
				curnode->symbol->info.linfo->address);
			free(curnode);
		}
	}
void
symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
{
	symbol_node_t *newnode;

	newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
	if (newnode == NULL) {
		stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
		/* NOTREACHED */
	}
	newnode->symbol = symbol;
	if (how == SYMLIST_SORT) {
		symbol_node_t *curnode;
		int mask;

		mask = FALSE;
		switch(symbol->type) {
		case REGISTER:
		case SCBLOC:
		case SRAMLOC:
			break;
		case BIT:
		case MASK:
			mask = TRUE;
			break;
		default:
			stop("symlist_add: Invalid symbol type for sorting",
			     EX_SOFTWARE);
			/* NOTREACHED */
		}

		curnode = SLIST_FIRST(symlist);
		if (curnode == NULL
		 || (mask && (curnode->symbol->info.minfo->mask >
		              newnode->symbol->info.minfo->mask))
		 || (!mask && (curnode->symbol->info.rinfo->address >
		               newnode->symbol->info.rinfo->address))) {
			SLIST_INSERT_HEAD(symlist, newnode, links);
			return;
		}

		while (1) {
			if (SLIST_NEXT(curnode, links) == NULL) {
				SLIST_INSERT_AFTER(curnode, newnode,
						   links);
				break;
			} else {
				symbol_t *cursymbol;

				cursymbol = SLIST_NEXT(curnode, links)->symbol;
				if ((mask && (cursymbol->info.minfo->mask >
				              symbol->info.minfo->mask))
				 || (!mask &&(cursymbol->info.rinfo->address >
				              symbol->info.rinfo->address))){
					SLIST_INSERT_AFTER(curnode, newnode,
							   links);
					break;
				}
			}
			curnode = SLIST_NEXT(curnode, links);
		}
	} else {
		SLIST_INSERT_HEAD(symlist, newnode, links);
	}
}
Example #6
0
/*
 * Load new table/tables to device.
 * Call apropriate target init routine open all physical pdev's and
 * link them to device. For other targets mirror, strip, snapshot
 * etc. also add dependency devices to upcalls list.
 *
 * Load table to inactive slot table are switched in dm_device_resume_ioctl.
 * This simulates Linux behaviour better there should not be any difference.
 *
 */
int
dm_table_load_ioctl(prop_dictionary_t dm_dict)
{
	dm_dev_t *dmv;
	dm_table_entry_t *table_en, *last_table;
	dm_table_t *tbl;
	dm_target_t *target;

	prop_object_iterator_t iter;
	prop_array_t cmd_array;
	prop_dictionary_t target_dict;

	const char *name, *uuid, *type;

	uint32_t flags, ret, minor;

	char *str;

	ret = 0;
	flags = 0;
	name = NULL;
	uuid = NULL;
	dmv = NULL;
	last_table = NULL;
	str = NULL;

	/*
	 * char *xml; xml = prop_dictionary_externalize(dm_dict);
	 * printf("%s\n",xml);
	 */

	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, &name);
	prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, &uuid);
	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &flags);
	prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor);

	cmd_array = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA);
	iter = prop_array_iterator(cmd_array);
	dm_dbg_print_flags(flags);

	if ((dmv = dm_dev_lookup(name, uuid, minor)) == NULL) {
		DM_REMOVE_FLAG(flags, DM_EXISTS_FLAG);
		return ENOENT;
	}
	aprint_debug("Loading table to device: %s--%d\n", name,
	    dmv->table_head.cur_active_table);

	/*
	 * I have to check if this table slot is not used by another table list.
	 * if it is used I should free them.
	 */
	if (dmv->flags & DM_INACTIVE_PRESENT_FLAG)
		dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);

	dm_dbg_print_flags(dmv->flags);
	tbl = dm_table_get_entry(&dmv->table_head, DM_TABLE_INACTIVE);

	aprint_debug("dmv->name = %s\n", dmv->name);

	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_MINOR, dmv->minor);

	while ((target_dict = prop_object_iterator_next(iter)) != NULL) {
		prop_dictionary_get_cstring_nocopy(target_dict,
		    DM_TABLE_TYPE, &type);
		/*
		 * If we want to deny table with 2 or more different
		 * target we should do it here
		 */
		if (((target = dm_target_lookup(type)) == NULL) &&
		    ((target = dm_target_autoload(type)) == NULL)) {
			dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
			dm_dev_unbusy(dmv);
			return ENOENT;
		}
		if ((table_en = kmalloc(sizeof(dm_table_entry_t),
			    M_DM, M_WAITOK)) == NULL) {
			dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
			dm_dev_unbusy(dmv);
			dm_target_unbusy(target);
			return ENOMEM;
		}
		prop_dictionary_get_uint64(target_dict, DM_TABLE_START,
		    &table_en->start);
		prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH,
		    &table_en->length);

		aprint_debug("dm_ioctl.c... table_en->start = %ju, "
			     "table_en->length = %ju\n",
			     (uintmax_t)table_en->start,
			     (uintmax_t)table_en->length);

		table_en->target = target;
		table_en->dm_dev = dmv;
		table_en->target_config = NULL;

		/*
		 * There is a parameter string after dm_target_spec
		 * structure which  points to /dev/wd0a 284 part of
		 * table. String str points to this text. This can be
		 * null and therefore it should be checked before we try to
		 * use it.
		 */
		prop_dictionary_get_cstring(target_dict,
		    DM_TABLE_PARAMS, &str);

		if (SLIST_EMPTY(tbl))
			/* insert this table to head */
			SLIST_INSERT_HEAD(tbl, table_en, next);
		else
			SLIST_INSERT_AFTER(last_table, table_en, next);

		/*
		 * Params string is different for every target,
		 * therfore I have to pass it to target init
		 * routine and parse parameters there.
		 */
		aprint_debug("DM: str passed in is: %s", str);
		if ((ret = target->init(dmv, &table_en->target_config,
			    str)) != 0) {

			dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);
			dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
			kfree(str, M_TEMP);

			dm_dev_unbusy(dmv);
			dm_target_unbusy(target);
			return ret;
		}
		last_table = table_en;
		kfree(str, M_TEMP);
	}
	prop_object_iterator_release(iter);

	DM_ADD_FLAG(flags, DM_INACTIVE_PRESENT_FLAG);
	atomic_set_int(&dmv->flags, DM_INACTIVE_PRESENT_FLAG);

	dm_table_release(&dmv->table_head, DM_TABLE_INACTIVE);

	dm_dev_unbusy(dmv);
#if 0
	dmsetdiskinfo(dmv->diskp, &dmv->table_head);
#endif
	return 0;
}
Example #7
0
void emulate_constructor(dmp_ctx_t *ctx, uint64_t constructor_address, struct hierarchy_entry_head *head)
{
    if (!ctx)
        return;
    if (!ctx->kimage_mh || !ctx->map || !ctx->reg_map)
        return;
    
    uint64_t kimage_base = find_kimage_base(ctx->kimage_mh);
    uint64_t kimage_os_metaclass_constructor = find_kimage_os_metaclass_constructor(ctx->kimage_mh, kimage_base);
    
    csh handle;
    cs_insn *insn;
    size_t count;
    
    cs_regs regs_read = {0}, regs_write = {0};
    uint8_t read_count, write_count;
    
    if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &handle) != CS_ERR_OK)
        return;
    
    cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
    
    uint8_t *constructor_code = (uint8_t *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, constructor_address);
    uint64_t constructor_size = get_constructor_size(ctx->kimage_mh, constructor_address, kimage_base);
    
    count = cs_disasm(handle, constructor_code, constructor_size, constructor_address, 0, &insn);
    if (count > 0) {
        size_t j;
        for (j = 0; j < count; j++) {
            if (cs_regs_access(handle, &insn[j], regs_read, &read_count, regs_write, &write_count) == 0) {
                switch (insn[j].id) {
                    case ARM64_INS_ADR: {
                        
                        uint64_t adr_addr = 0;
                        int is_adrp = 0;
                        uint32_t rd = 0;
                        int32_t off = 0;
                        if (aarch64_decode_adr(*(uint32_t *)(&insn[j].bytes), &is_adrp, &rd, &off)) {
                            adr_addr = insn[j].address + off;
                        }
                        
                        get_ctx_reg_map_reg(ctx, regs_write[0]) = adr_addr;
                        break;
                    }
                        
                    case ARM64_INS_ADRP: {
                        
                        uint64_t adr_addr = 0;
                        int is_adrp = 0;
                        uint32_t rd = 0;
                        int32_t off = 0;
                        if (aarch64_decode_adr(*(uint32_t *)(&insn[j].bytes), &is_adrp, &rd, &off)) {
                            adr_addr = ((insn[j].address + off) >> 12) << 12;
                        }
                        
                        get_ctx_reg_map_reg(ctx, regs_write[0]) = adr_addr;
                        break;
                    }
                        
                    case ARM64_INS_LDR: {
                        
                        uint64_t ldr_addr = 0;
                        int is_w = 0;
                        int is64 = 0;
                        uint32_t rt = 0;
                        
                        int32_t s_off = 0;
                        uint32_t u_off = 0;
                        
                        if (aarch64_decode_ldr_literal(*(uint32_t *)(&insn[j].bytes), &is_w, &is64, &rt, &s_off)) {
                            ldr_addr = insn[j].address + s_off;
                            uint64_t ldr_deref = *(uint64_t *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, ldr_addr);
                            get_ctx_reg_map_reg(ctx, regs_write[0]) = ldr_deref;
                        } else if (aarch64_decode_ldr_immediate(*(uint32_t *)(&insn[j].bytes), &u_off)) {
                            uint64_t op1 = get_ctx_reg_map_reg(ctx, regs_read[0]);
                            op1 += u_off;
                            
                            uint64_t ldr_addr = *(uint64_t *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, op1);
                            get_ctx_reg_map_reg(ctx, regs_write[0]) = ldr_addr;
                        }
                        
                        break;
                    }
                        
                    case ARM64_INS_ADD: {

                        uint32_t off = 0;
                        if (aarch64_decode_add(*(uint32_t *)(&insn[j].bytes), &off)) {
                            uint64_t op1 = get_ctx_reg_map_reg(ctx, regs_read[0]);
                            op1 += off;
                            get_ctx_reg_map_reg(ctx, regs_write[0]) = op1;
                        }
                        
                        break;
                    }
                        
                    case ARM64_INS_MOV: {
                        
                        uint64_t op1 = get_ctx_reg_map_reg(ctx, regs_read[0]);
                        get_ctx_reg_map_reg(ctx, regs_write[0]) = op1;
                        
                        break;
                    }
                     
                    /* ugly. libdump should be independent of iokitdumper, but I was lazy and this was the quickest way to map constructors lmao */
                    case ARM64_INS_BL: {
                        
                        int is_bl = 0;
                        int32_t off = 0;
                        if (aarch64_decode_b(*(uint32_t *)(&insn[j].bytes), &is_bl, &off)) {
                            if (insn[j].address + off == kimage_os_metaclass_constructor) {
                                
                                const char *kext_name = get_kext_name(ctx->map, ctx->kimage_mh);
                                
                                struct hierarchy_entry *entry = malloc(sizeof(struct hierarchy_entry));
                                
                                strncpy(entry->class_name, (char *)KERNEL_ADDR_TO_MAP(ctx->kimage_mh, kimage_base, get_ctx_reg_map_reg(ctx, REG_X1)), sizeof(entry->class_name));
                                if (kext_name)
                                    strncpy(entry->kext_name, kext_name, sizeof(entry->kext_name));
                                else {
                                    if (((void *)ctx->map->map_data == (void *)ctx->kimage_mh)) {
                                        strncpy(entry->kext_name, "kernel", sizeof(entry->kext_name));
                                    } else {
                                        strncpy(entry->kext_name, "unknown", sizeof(entry->kext_name));
                                    }
                                }
                                
                                struct hierarchy_regs_set set = {0};
                                set.reg_x0 = get_ctx_reg_map_reg(ctx, REG_X0);
                                set.reg_x1 = get_ctx_reg_map_reg(ctx, REG_X1);
                                set.reg_x2 = get_ctx_reg_map_reg(ctx, REG_X2);
                                
                                entry->set = set;
                                
                                if (head) {
                                    if (SLIST_EMPTY(head)) {
                                        SLIST_INSERT_HEAD(head, entry, entries);
                                        prev = entry;
                                    } else {
                                        SLIST_INSERT_AFTER(prev, entry, entries);
                                        prev = entry;
                                    }
                                } else {
                                    free(entry);
                                }
                            }
                        }
                        
                        break;
                    }
                }
            }
        }