static int is_prd_supported(void) { char *path; int rc; int len; char *buf; rc = asprintf(&path, "%s/ibm,opal/diagnostics/compatible", devicetree_base); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'compatible' node path: %m"); return -1; } rc = open_and_read(path, (void *) &buf, &len); if (rc) goto out_free; if (buf[len - 1] != '\0') pr_log(LOG_INFO, "FW: node %s is not nul-terminated", path); rc = find_string(buf, len, "ibm,opal-prd") ? 0 : -1; free(buf); out_free: free(path); return rc; }
int pe2obj(int argc, char **argv) { // decleration before more meaningful initialization for cleanup int ret = EXIT_SUCCESS; FILE *fh = NULL; int8_t *image = NULL; FAIL_IF(argc != 3, "usage: petool pe2obj <in> <out>\n"); uint32_t length; FAIL_IF_SILENT(open_and_read(&fh, &image, &length, argv[1], "rb")); fclose(fh); fh = NULL; // for cleanup PIMAGE_DOS_HEADER dos_hdr = (void *)image; PIMAGE_NT_HEADERS nt_hdr = (void *)(image + dos_hdr->e_lfanew); FAIL_IF(length < 512, "File too small.\n"); FAIL_IF(dos_hdr->e_magic != IMAGE_DOS_SIGNATURE, "File DOS signature invalid.\n"); FAIL_IF(nt_hdr->Signature != IMAGE_NT_SIGNATURE, "File NT signature invalid.\n"); for (int i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++) { const PIMAGE_SECTION_HEADER cur_sct = IMAGE_FIRST_SECTION(nt_hdr) + i; if (cur_sct->PointerToRawData) { cur_sct->PointerToRawData -= dos_hdr->e_lfanew + 4; } if (cur_sct->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA && !(cur_sct->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)) { cur_sct->PointerToRawData = 0; cur_sct->SizeOfRawData = 0; } } fh = fopen(argv[2], "wb"); FAIL_IF_PERROR(!fh, "Error opening output file"); FAIL_IF_PERROR(fwrite((char *)image + (dos_hdr->e_lfanew + 4), length - (dos_hdr->e_lfanew + 4), 1, fh) != 1, "Failed to write object file to output file\n"); cleanup: if (image) free(image); if (fh) fclose(fh); return ret; }
int setvs(int argc, char **argv) { // decleration before more meaningful initialization for cleanup int ret = EXIT_SUCCESS; FILE *fh = NULL; int8_t *image = NULL; FAIL_IF(argc != 4, "usage: petool setvs <image> <section> <VirtualSize>\n"); uint32_t vs = strtol(argv[3], NULL, 0); uint32_t length; FAIL_IF_SILENT(open_and_read(&fh, &image, &length, argv[1], "r+b")); PIMAGE_DOS_HEADER dos_hdr = (void *)image; PIMAGE_NT_HEADERS nt_hdr = (void *)(image + dos_hdr->e_lfanew); FAIL_IF(length < sizeof (IMAGE_DOS_HEADER), "File too small.\n"); FAIL_IF(dos_hdr->e_magic != IMAGE_DOS_SIGNATURE, "File DOS signature invalid.\n"); FAIL_IF(dos_hdr->e_lfanew == 0, "NT header missing.\n"); FAIL_IF(nt_hdr->Signature != IMAGE_NT_SIGNATURE, "File NT signature invalid.\n"); FAIL_IF(vs == 0, "VirtualSize can't be zero.\n"); for (int32_t i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++) { PIMAGE_SECTION_HEADER sct_hdr = IMAGE_FIRST_SECTION(nt_hdr) + i; if (strcmp(argv[2], (char *)sct_hdr->Name) == 0) { FAIL_IF(vs < sct_hdr->SizeOfRawData,"VirtualSize can't be smaller than raw size.\n"); sct_hdr->Misc.VirtualSize = vs; // update section size // update total virtual size of image nt_hdr->OptionalHeader.SizeOfImage += vs - sct_hdr->Misc.VirtualSize; nt_hdr->OptionalHeader.CheckSum = 0; // FIXME: implement checksum calculation rewind(fh); // write to file FAIL_IF_PERROR(fwrite(image, length, 1, fh) != 1, "Error writing executable"); goto cleanup; // done } } fprintf(stderr, "No '%s' section in given PE image.\n", argv[2]); cleanup: if (image) free(image); if (fh) fclose(fh); return ret; }
static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path, struct dirent *dirent) { char *label_path, *reg_path, *instance_path; struct prd_range *range; int label_len, len, rc; __be64 *reg; char *label; void *buf; rc = asprintf(&label_path, "%s/%s/ibm,prd-label", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'ibm,prd-label' path " "node: %m"); return -1; } rc = asprintf(&instance_path, "%s/%s/ibm,prd-instance", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'ibm,prd-instance' path " "node: %m"); return -1; } rc = asprintf(®_path, "%s/%s/reg", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'reg' path " " node: %m"); return -1; } reg = NULL; label = NULL; rc = -1; rc = open_and_read(label_path, &buf, &label_len); if (rc) goto out_free; label = buf; if (label[label_len-1] != '\0') pr_log(LOG_INFO, "FW: node %s has invalid ibm,prd-label - " "not nul-terminated", dirent->d_name); rc = open_and_read(reg_path, &buf, &len); if (rc) goto out_free; reg = buf; if (len != 2 * sizeof(*reg)) { pr_log(LOG_ERR, "FW: node %s has invalid 'reg' size: %d", dirent->d_name, len); goto out_free; } ctx->ranges = realloc(ctx->ranges, ++ctx->n_ranges * sizeof(*range)); range = &ctx->ranges[ctx->n_ranges - 1]; range->name = strndup(label, label_len); range->physaddr = be64toh(reg[0]); range->size = be64toh(reg[1]); range->buf = NULL; range->multiple = false; range->instance = 0; /* optional instance */ rc = open_and_read(instance_path, &buf, &len); if (!rc && len == sizeof(uint32_t)) { range->multiple = true; range->instance = be32toh(*(uint32_t *)buf); ctx->fw_range_instances = true; } rc = 0; out_free: free(reg); free(label); free(instance_path); free(reg_path); free(label_path); return rc; }
int genmak(int argc, char **argv) { int ret = EXIT_SUCCESS; FILE *fh = NULL; int8_t *image = NULL; FILE *ofh = stdout; char base[256] = { '\0' }; FAIL_IF(argc < 2, "usage: petool genmak <image> [ofile]\n"); if (argc > 2) { FAIL_IF(file_exists(argv[2]), "%s: output file already exists.\n", argv[2]); ofh = fopen(argv[2], "w"); FAIL_IF_PERROR(ofh == NULL, "%s"); } uint32_t length; FAIL_IF_SILENT(open_and_read(&fh, &image, &length, argv[1], "rb")); fclose(fh); fh = NULL; // for cleanup PIMAGE_DOS_HEADER dos_hdr = (void *)image; PIMAGE_NT_HEADERS nt_hdr = (void *)(image + dos_hdr->e_lfanew); FAIL_IF(length < 512, "File too small.\n"); FAIL_IF(dos_hdr->e_magic != IMAGE_DOS_SIGNATURE, "File DOS signature invalid.\n"); FAIL_IF(nt_hdr->Signature != IMAGE_NT_SIGNATURE, "File NT signature invalid.\n"); strcpy(base, file_basename(argv[1])); char *p = strrchr(base, '.'); if (p) { *p = '\0'; } fprintf(ofh, "-include config.mk\n\n"); fprintf(ofh, "INPUT = %s\n", file_basename(argv[1])); fprintf(ofh, "OUTPUT = %sp.exe\n", base); fprintf(ofh, "LDS = %sp.lds\n", base); fprintf(ofh, "IMPORTS ="); if (nt_hdr->OptionalHeader.DataDirectory[1].VirtualAddress) { fprintf(ofh, " 0x%"PRIX32" %d", nt_hdr->OptionalHeader.DataDirectory[1].VirtualAddress, nt_hdr->OptionalHeader.DataDirectory[1].Size); } fprintf(ofh, "\n"); fprintf(ofh, "LDFLAGS = --section-alignment=0x%"PRIX32, nt_hdr->OptionalHeader.SectionAlignment); if (nt_hdr->OptionalHeader.Subsystem == 2) fprintf(ofh, " --subsystem=windows"); fprintf(ofh, "\n\n"); fprintf(ofh, "OBJS = rsrc.o\n\n"); fprintf(ofh, "PETOOL ?= petool\n"); fprintf(ofh, "STRIP ?= strip\n\n"); fprintf(ofh, "all: $(OUTPUT)\n\n"); fprintf(ofh, "rsrc.o: $(INPUT)\n"); fprintf(ofh, "\t$(PETOOL) re2obj $(INPUT) $@\n\n"); fprintf(ofh, "$(OUTPUT): $(LDS) $(INPUT) $(OBJS)\n"); fprintf(ofh, "\t$(LD) $(LDFLAGS) -T $(LDS) -o $@ $(OBJS)\n"); fprintf(ofh, "ifneq (,$(IMPORTS))\n"); fprintf(ofh, "\t$(PETOOL) setdd $@ 1 $(IMPORTS) || ($(RM) $@ && exit 1)\n"); fprintf(ofh, "endif\n"); fprintf(ofh, "\t$(PETOOL) patch $@ || ($(RM) $@ && exit 1)\n"); fprintf(ofh, "\t$(STRIP) -R .patch $@ || ($(RM) $@ && exit 1)\n"); fprintf(ofh, "\t$(PETOOL) dump $@\n\n"); fprintf(ofh, "clean:\n"); fprintf(ofh, "\t$(RM) $(OUTPUT) $(OBJS)\n"); cleanup: if (argc > 2) { if (ofh) fclose(ofh); } if (image) free(image); if (fh) fclose(fh); return ret; }
int patch(int argc, char **argv) { // decleration before more meaningful initialization for cleanup int ret = EXIT_FAILURE; FILE *fh = NULL; int8_t *image = NULL; FAIL_IF(argc < 2, "usage: petool patch <image> [section]\n"); uint32_t length; FAIL_IF_SILENT(open_and_read(&fh, &image, &length, argv[1], "r+b")); PIMAGE_DOS_HEADER dos_hdr = (void *)image; PIMAGE_NT_HEADERS nt_hdr = (void *)(image + dos_hdr->e_lfanew); char *section = argc > 2 ? (char *)argv[2] : ".patch"; int8_t *patch = NULL; int32_t patch_len = 0; for (int32_t i = 0; i < nt_hdr->FileHeader.NumberOfSections; i++) { PIMAGE_SECTION_HEADER sct_hdr = IMAGE_FIRST_SECTION(nt_hdr) + i; if (strcmp(section, (char *)sct_hdr->Name) == 0) { patch = image + sct_hdr->PointerToRawData; patch_len = sct_hdr->Misc.VirtualSize; break; } sct_hdr++; } if (patch == NULL) { fprintf(stderr, "Warning: No '%s' section in given PE image.\n", section); ret = EXIT_SUCCESS; goto cleanup; } for (int8_t *p = patch; p < patch + patch_len;) { uint32_t paddress = get_uint32(&p); if (paddress == 0) { fprintf(stderr, "Warning: Trailing zero address in '%s' section.\n", section); break; } uint32_t plength = get_uint32(&p); FAIL_IF_SILENT(patch_image(image, paddress, p, plength) == EXIT_FAILURE); p += plength; } /* FIXME: implement checksum calculation */ nt_hdr->OptionalHeader.CheckSum = 0; rewind(fh); FAIL_IF_PERROR(fwrite(image, length, 1, fh) != 1, "Error writing executable"); ret = EXIT_SUCCESS; cleanup: if (image) free(image); if (fh) fclose(fh); return ret; }