struct r_bin_pe_export_t* PE_(r_bin_pe_get_exports)(struct PE_(r_bin_pe_obj_t)* bin) {
	struct r_bin_pe_export_t* exp, * exports = NULL;
	PE_Word function_ordinal;
	PE_VWord functions_paddr, names_paddr, ordinals_paddr, function_rva, name_vaddr, name_paddr;
	char function_name[PE_NAME_LENGTH + 1], forwarder_name[PE_NAME_LENGTH + 1];
	char dll_name[PE_NAME_LENGTH + 1], export_name[256];
	PE_(image_data_directory) * data_dir_export;
	PE_VWord export_dir_rva;
	int n,i, export_dir_size;
	st64 exports_sz = 0;

	if (!bin || !bin->data_directory) {
		return NULL;
	}
	data_dir_export = &bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_EXPORT];
	export_dir_rva = data_dir_export->VirtualAddress;
	export_dir_size = data_dir_export->Size;
	if (bin->export_directory) {
		if (bin->export_directory->NumberOfFunctions + 1 <
		bin->export_directory->NumberOfFunctions) {
			// avoid integer overflow
			return NULL;
		}
		exports_sz = (bin->export_directory->NumberOfFunctions + 1) * sizeof (struct r_bin_pe_export_t);
		// we cant exit with export_sz > bin->size, us r_bin_pe_export_t is 256+256+8+8+8+4 bytes is easy get over file size
		// to avoid fuzzing we can abort on export_directory->NumberOfFunctions>0xffff
		if (exports_sz < 0 || bin->export_directory->NumberOfFunctions + 1 > 0xffff) {
			return NULL;
		}
		if (!(exports = malloc (exports_sz))) {
			return NULL;
		}
		if (r_buf_read_at (bin->b, bin_pe_rva_to_paddr (bin, bin->export_directory->Name), (ut8*) dll_name, PE_NAME_LENGTH) < 1) {
			bprintf ("Warning: read (dll name)\n");
			free (exports);
			return NULL;
		}
		functions_paddr = bin_pe_rva_to_paddr (bin, bin->export_directory->AddressOfFunctions);
		names_paddr = bin_pe_rva_to_paddr (bin, bin->export_directory->AddressOfNames);
		ordinals_paddr = bin_pe_rva_to_paddr (bin, bin->export_directory->AddressOfOrdinals);
		for (i = 0; i < bin->export_directory->NumberOfFunctions; i++) {
			// get vaddr from AddressOfFunctions array
			int ret = r_buf_read_at (bin->b, functions_paddr + i * sizeof(PE_VWord), (ut8*) &function_rva, sizeof(PE_VWord));
			if (ret < 1) {
				break;
			}
			// have exports by name?
			if (bin->export_directory->NumberOfNames != 0) {
				// search for value of i into AddressOfOrdinals
				name_vaddr = 0;
				for (n = 0; n < bin->export_directory->NumberOfNames; n++) {
					ret = r_buf_read_at (bin->b, ordinals_paddr + n * sizeof(PE_Word), (ut8*) &function_ordinal, sizeof (PE_Word));
					if (ret < 1) {
						break;
					}
					// if exist this index into AddressOfOrdinals
					if (i == function_ordinal) {
						// get the VA of export name  from AddressOfNames
						r_buf_read_at (bin->b, names_paddr + n * sizeof (PE_VWord), (ut8*) &name_vaddr, sizeof (PE_VWord));
						break;
					}
				}
				// have an address into name_vaddr?
				if (name_vaddr) {
					// get the name of the Export
					name_paddr = bin_pe_rva_to_paddr (bin, name_vaddr);
					if (r_buf_read_at (bin->b, name_paddr, (ut8*) function_name, PE_NAME_LENGTH) < 1) {
						bprintf ("Warning: read (function name)\n");
						exports[i].last = 1;
						return exports;
					}
				} else { // No name export, get the ordinal
					snprintf (function_name, PE_NAME_LENGTH, "Ordinal_%i", i + 1);
				}
			}else { // if dont export by name exist, get the ordinal taking in mind the Base value.
				function_ordinal = i + bin->export_directory->Base;
				snprintf (function_name, PE_NAME_LENGTH, "Ordinal_%i", function_ordinal);
			}
			// check if VA are into export directory, this mean a forwarder export
			if (function_rva >= export_dir_rva && function_rva < (export_dir_rva + export_dir_size)) {
				// if forwarder, the VA point to Forwarded name
				if (r_buf_read_at (bin->b, bin_pe_rva_to_paddr (bin, function_rva), (ut8*) forwarder_name, PE_NAME_LENGTH) < 1) {
					exports[i].last = 1;
					return exports;
				}
			} else { // no forwarder export
				snprintf (forwarder_name, PE_NAME_LENGTH, "NONE");
			}
			dll_name[PE_NAME_LENGTH] = '\0';
			function_name[PE_NAME_LENGTH] = '\0';
			snprintf (export_name, sizeof (export_name) - 1, "%s_%s", dll_name, function_name);
			exports[i].vaddr = bin_pe_rva_to_va (bin, function_rva);
			exports[i].paddr = bin_pe_rva_to_paddr (bin, function_rva);
			exports[i].ordinal = function_ordinal;
			memcpy (exports[i].forwarder, forwarder_name, PE_NAME_LENGTH);
			exports[i].forwarder[PE_NAME_LENGTH] = '\0';
			memcpy (exports[i].name,      export_name,    PE_NAME_LENGTH);
			exports[i].name[PE_NAME_LENGTH] = '\0';
			exports[i].last = 0;
		}
		exports[i].last = 1;
	}
	exp = parse_symbol_table (bin, exports, exports_sz - 1);
	if (exp) {
		exports = exp;
	}
	return exports;
}