RZ_API RZ_OWN RzList /*<RzBinSymbol *>*/ *rz_bin_dex_symbols(RZ_NONNULL RzBinDex *dex) {
	rz_return_val_if_fail(dex, NULL);

	DexClassDef *class_def;
	DexFieldId *field_id;
	DexMethodId *method_id;
	RzList *class_symbols = NULL;
	RzList *symbols = NULL;
	void **vit;
	ut8 *inserted_methods = NULL;
	ut8 *inserted_fields = NULL;
	ut32 n_methods = rz_pvector_len(dex->method_ids);
	ut32 n_fields = rz_pvector_len(dex->field_ids);

	inserted_methods = RZ_NEWS0(ut8, n_methods);
	inserted_fields = RZ_NEWS0(ut8, n_fields);
	if ((n_methods > 0 && !inserted_methods) || (n_fields > 0 && !inserted_fields)) {
		free(inserted_fields);
		free(inserted_methods);
		return NULL;
	}

	symbols = rz_list_newf((RzListFree)rz_bin_symbol_free);
	if (!symbols) {
		free(inserted_fields);
		free(inserted_methods);
		return NULL;
	}

	rz_pvector_foreach (dex->class_defs, vit) {
		class_def = (DexClassDef *)*vit;

		class_symbols = dex_resolve_fields_in_class_as_symbols(dex, class_def, inserted_fields);
		if (class_symbols) {
			rz_list_join(symbols, class_symbols);
			rz_list_free(class_symbols);
		}

		class_symbols = dex_resolve_methods_in_class(dex, class_def, inserted_methods);
		if (class_symbols) {
			rz_list_join(symbols, class_symbols);
			rz_list_free(class_symbols);
		}
	}

	ut32 j = 0;
	rz_pvector_foreach (dex->field_ids, vit) {
		field_id = (DexFieldId *)*vit;
		if (inserted_fields[j++]) {
			continue;
		}

		RzBinSymbol *field = RZ_NEW0(RzBinSymbol);
		if (!field) {
			break;
		}

		field->name = dex_resolve_string_id(dex, field_id->name_idx);
		field->classname = dex_resolve_type_id(dex, field_id->class_idx);
		field->libname = dex_resolve_library(field->classname);
		field->bind = RZ_BIN_BIND_WEAK_STR;
		field->type = RZ_BIN_TYPE_FIELD_STR;
		field->is_imported = true;

		if (!rz_list_append(symbols, field)) {
			rz_bin_symbol_free(field);
			break;
		}
	}

	j = 0;
	rz_pvector_foreach (dex->method_ids, vit) {
		method_id = (DexMethodId *)*vit;
		if (inserted_methods[j++]) {
			continue;
		}

		RzBinSymbol *method = RZ_NEW0(RzBinSymbol);
		if (!method) {
			break;
		}

		method->name = dex_resolve_string_id(dex, method_id->name_idx);
		method->classname = dex_resolve_type_id(dex, method_id->class_idx);
		method->libname = dex_resolve_library(method->classname);
		method->dname = dex_resolve_proto_id(dex, method->name, method_id->proto_idx, false);
		method->bind = RZ_BIN_BIND_WEAK_STR;
		method->is_imported = true;
		method->type = RZ_BIN_TYPE_METH_STR;
		if (method_id->code_offset < RZ_DEX_RELOC_ADDRESS) {
			method->vaddr = RZ_DEX_VIRT_ADDRESS + method_id->code_offset;
			method->paddr = method_id->code_offset;
		} else {
			method->vaddr = method_id->code_offset;
			method->paddr = 0;
		}
		method->size = method_id->code_size;

		if (!rz_list_append(symbols, method)) {
			rz_bin_symbol_free(method);
			break;
		}
	}

	free(inserted_fields);
	free(inserted_methods);
	return symbols;
}
RZ_API RZ_OWN RzList   *rz_bin_dex_symbols(RZ_NONNULL RzBinDex *dex) {
	rz_return_val_if_fail(dex, NULL);

	DexClassDef *class_def;
	DexFieldId *field_id;
	DexMethodId *method_id;
	RzList *class_symbols = NULL;
	RzList *symbols = NULL;
	void **vit;
	ut8 *inserted_methods = NULL;
	ut8 *inserted_fields = NULL;
	ut32 n_methods = rz_pvector_len(dex->method_ids);
	ut32 n_fields = rz_pvector_len(dex->field_ids);

	inserted_methods = RZ_NEWS0(ut8, n_methods);
	inserted_fields = RZ_NEWS0(ut8, n_fields);
	if ((n_methods > 0 && !inserted_methods) || (n_fields > 0 && !inserted_fields)) {
		free(inserted_fields);
		free(inserted_methods);
		return NULL;
	}

	symbols = rz_list_newf((RzListFree)rz_bin_symbol_free);
	if (!symbols) {
		free(inserted_fields);
		free(inserted_methods);
		return NULL;
	}

	rz_pvector_foreach (dex->class_defs, vit) {
		class_def = (DexClassDef *)*vit;

		class_symbols = dex_resolve_fields_in_class_as_symbols(dex, class_def, inserted_fields);
		if (class_symbols) {
			rz_list_join(symbols, class_symbols);
			rz_list_free(class_symbols);
		}

		class_symbols = dex_resolve_methods_in_class(dex, class_def, inserted_methods);
		if (class_symbols) {
			rz_list_join(symbols, class_symbols);
			rz_list_free(class_symbols);
		}
	}

	ut32 j = 0;
	rz_pvector_foreach (dex->field_ids, vit) {
		field_id = (DexFieldId *)*vit;
		if (inserted_fields[j++]) {
			continue;
		}

		RzBinSymbol *field = RZ_NEW0(RzBinSymbol);
		if (!field) {
			break;
		}

		field->name = dex_resolve_string_id(dex, field_id->name_idx);
		field->classname = dex_resolve_type_id(dex, field_id->class_idx);
		field->libname = dex_resolve_library(field->classname);
		field->bind = RZ_BIN_BIND_WEAK_STR;
		field->type = RZ_BIN_TYPE_FIELD_STR;
		field->is_imported = true;

		if (!rz_list_append(symbols, field)) {
			rz_bin_symbol_free(field);
			break;
		}
	}

	j = 0;
	rz_pvector_foreach (dex->method_ids, vit) {
		method_id = (DexMethodId *)*vit;
		if (inserted_methods[j++]) {
			continue;
		}

		RzBinSymbol *method = RZ_NEW0(RzBinSymbol);
		if (!method) {
			break;
		}

		method->name = dex_resolve_string_id(dex, method_id->name_idx);
		method->classname = dex_resolve_type_id(dex, method_id->class_idx);
		method->libname = dex_resolve_library(method->classname);
		method->dname = dex_resolve_proto_id(dex, method->name, method_id->proto_idx, false);
		method->bind = RZ_BIN_BIND_WEAK_STR;
		method->is_imported = true;
		method->type = RZ_BIN_TYPE_METH_STR;
		if (method_id->code_offset < RZ_DEX_RELOC_ADDRESS) {
			method->vaddr = RZ_DEX_VIRT_ADDRESS + method_id->code_offset;
			method->paddr = method_id->code_offset;
		} else {
			method->vaddr = method_id->code_offset;
			method->paddr = 0;
		}
		method->size = method_id->code_size;

		if (!rz_list_append(symbols, method)) {
			rz_bin_symbol_free(method);
			break;
		}
	}

	free(inserted_fields);
	free(inserted_methods);
	return symbols;
}