int flash_rockbox(const char *filename, int section) { struct flash_header hdr; int pos, i, len, rc; unsigned long checksum, sum; unsigned char *p8; uint16_t *p16; if (get_section_address(section) < 0) return -1; p8 = (char *)BOOTLOADER_ENTRYPOINT; if (!detect_valid_bootloader(p8, 0)) { rb->splash(HZ*3, "Incompatible bootloader"); return -1; } if (!rb->detect_original_firmware()) { if (!confirm("Update Rockbox flash image?")) return -2; } else { if (!confirm("Erase original firmware?")) return -3; } len = load_firmware_file(filename, &checksum); if (len <= 0) return len * 10; pos = get_section_address(section); /* Check if image relocation seems to be sane. */ if (section == SECT_ROMIMAGE) { uint32_t *p32 = (uint32_t *)audiobuf; if (pos+sizeof(struct flash_header) != *p32) { rb->splashf(HZ*10, "Incorrect relocation: 0x%08lx/0x%08lx", *p32, pos+sizeof(struct flash_header)); return -1; } } /* Erase the program flash. */ for (i = 0; i + pos < BOOTLOADER_ENTRYPOINT && i < len + 32; i += SEC_SIZE) { /* Additional safety check. */ if (i + pos < SEC_SIZE) return -1; rb->lcd_putsf(0, 3, "Erasing... %d%%", (i+SEC_SIZE)*100/len); rb->lcd_update(); rc = cfi_erase_sector(FB + (i + pos)/2); } /* Write the magic and size. */ rb->memset(&hdr, 0, sizeof(struct flash_header)); hdr.magic = FLASH_MAGIC; hdr.length = len; // rb->strncpy(hdr.version, rb->rbversion , sizeof(hdr.version)-1); p16 = (uint16_t *)&hdr; rb->lcd_puts(0, 4, "Programming..."); rb->lcd_update(); pos = get_section_address(section)/2; for (i = 0; i < (long)sizeof(struct flash_header)/2; i++) { cfi_program_word(FB + pos, p16[i]); pos++; } p16 = (uint16_t *)audiobuf; for (i = 0; i < len/2 && pos + i < (BOOTLOADER_ENTRYPOINT/2); i++) { if (i % SEC_SIZE == 0) { rb->lcd_putsf(0, 4, "Programming... %d%%", (i+1)*100/(len/2)); rb->lcd_update(); } cfi_program_word(FB + pos + i, p16[i]); } /* Verify */ rb->lcd_puts(0, 5, "Verifying"); rb->lcd_update(); p8 = (char *)get_section_address(section); p8 += sizeof(struct flash_header); sum = MODEL_NUMBER; for (i = 0; i < len; i++) sum += p8[i]; if (sum != checksum) { rb->splash(HZ*3, "Verify failed!"); /* Erase the magic sector so bootloader does not try to load * rockbox from flash and crash. */ if (section == SECT_RAMIMAGE) cfi_erase_sector(FB + FLASH_RAMIMAGE_ENTRY/2); else cfi_erase_sector(FB + FLASH_ROMIMAGE_ENTRY/2); return -5; } rb->splash(HZ*2, "Success"); return 0; }
int build_code_profile(handle_t *h) { csh disas_handle; cs_insn *insn; size_t count; int mode = h->arch == 32 ? CS_MODE_32 : CS_MODE_64; ElfW(Off) offset = h->elf.entry - h->elf.textVaddr; uint8_t *code = &h->elf.mem[offset]; struct branch_instr *branch_instr; unsigned long target_address, callsite; char *tmp; int c, argc; if (cs_open(CS_ARCH_X86, CS_MODE_64, &disas_handle) != CS_ERR_OK) return -1; ElfW(Addr) dot_text = get_section_address(h, ".text"); /* if (dot_text != 0) { size_t text_section_size = get_section_size(h, ".text"); count = cs_disasm_ex(disas_handle, code, text_section_size, dot_text, 0, &insn); } else */ count = cs_disasm_ex(disas_handle, code, h->elf.textSize, h->elf.entry, 0, &insn); if (count < 1) { fprintf(stderr, "Failed to disassemble code\n"); return -1; } size_t j; for (j = 0; j < count; j++) { //if (opts.debug) /* * Is the instruction a type of jmp? */ if ((branch_instr = search_branch_instr(insn[j].bytes[0])) != NULL) { /* Found a non-call branch instruction */ h->branch_site[h->branch_count].branch_type = IMMEDIATE_JMP; h->branch_site[h->branch_count].branch.location = callsite = insn[j].address; h->branch_site[h->branch_count].branch.target_vaddr = target_address = strtoul(insn[j].op_str, NULL, 16); h->branch_site[h->branch_count].branch.target_offset = target_address - callsite - 1; h->branch_site[h->branch_count].branch.mnemonic = xstrdup(insn[j].mnemonic); if (opts.debug) printf("[+] Storing information for instruction: jmp %lx\n", target_address); h->branch_count++; continue; } /* * Is the instruction a call? */ if ((strncmp(insn[j].mnemonic, "call", 4) != 0)) continue; /* * Which type of call? */ switch(insn[j].bytes[0]) { case 0xE8: h->branch_site[h->branch_count].branch_type = IMMEDIATE_CALL; h->branch_site[h->branch_count].branch.location = callsite = insn[j].address; h->branch_site[h->branch_count].branch.target_vaddr = target_address = strtoul(insn[j].op_str, NULL, 16); h->branch_site[h->branch_count].branch.target_offset = target_address - callsite - sizeof(uint32_t); h->branch_site[h->branch_count].branch.ret_target = insn[j + 1].address; h->branch_site[h->branch_count].branch.mnemonic = xstrdup(insn[j].mnemonic); if ((tmp = get_fn_name(h, target_address)) != NULL) h->branch_site[h->branch_count].branch.function = xstrdup(tmp); else tmp = h->branch_site[h->branch_count].branch.function = xfmtstrdup("sub_%lx", target_address); if (fn_is_local(h, tmp)) h->branch_site[h->branch_count].branch.calltype = LOCAL_CALL; else h->branch_site[h->branch_count].branch.calltype = PLT_CALL; int t; for (argc = 0, c = 0; c < MAX_ARGS; c++) { switch(c) { case 0: argc += check_for_reg(insn[j - (c + 1)].op_str, EDI); break; case 1: argc += check_for_reg(insn[j - (c + 1)].op_str, ESI); break; case 2: argc += check_for_reg(insn[j - (c + 1)].op_str, EDX); break; case 3: argc += check_for_reg(insn[j - (c + 1)].op_str, ECX); break; case 4: argc += check_for_reg(insn[j - (c + 1)].op_str, R8D); break; case 5: argc += check_for_reg(insn[j - (c + 1)].op_str, R9D); break; } } /* * We search to see if the same function has been called before, and if so * is the argument count larger than what we just found? If so then use that * argc value because it is likely correct over the one we just found (Which may * be thrown off due to gcc optimizations */ h->branch_site[h->branch_count].branch.argc = argc; for (c = 0; c < h->branch_count; c++) { if (h->branch_site[c].branch_type != IMMEDIATE_CALL) continue; if (!strcmp(h->branch_site[c].branch.function, h->branch_site[h->branch_count].branch.function)) if (h->branch_site[c].branch.argc > argc) h->branch_site[h->branch_count].branch.argc = h->branch_site[c].branch.argc; } int r; int found_edi = 0; int found_esi = 0; int found_edx = 0; int found_ecx = 0; int found_r9 = 0; int found_r8 = 0; int k = 0; if (argc == 0) { /* Try aggressive arg resolution */ for (c = 0; c < MAX_ARGS + 4; c++) { argc += r = check_for_reg(insn[j - (c + 1)].op_str, EDI); if (r != 0) { found_edi++; break; } } if (found_edi) { for (c = 0; c < MAX_ARGS + 4; c++) { argc += r = check_for_reg(insn[j - (c + 1)].op_str, ESI); if (r != 0) { found_esi++; break; } } } if (found_esi) { for (c = 0; c < MAX_ARGS + 4; c++) { argc += r = check_for_reg(insn[j - (c + 1)].op_str, EDX); if (r != 0) { found_edx++; break; } } } if (found_edx) { for (c = 0; c < MAX_ARGS + 4; c++) { argc += r = check_for_reg(insn[j - (c + 1)].op_str, ECX); if (r != 0) { found_ecx++; break; } } } if (found_ecx) { for (c = 0; c < MAX_ARGS + 4; c++) { argc += r = check_for_reg(insn[j - (c + 1)].op_str, R8D); if (r != 0) { found_r8++; break; } } } if (found_r8) { for (c = 0; c < MAX_ARGS + 4; c++) { argc += r = check_for_reg(insn[j - (c + 2)].op_str, R9D); if (r != 0) { found_r9++; break; } } } h->branch_site[h->branch_count].branch.argc = argc; } h->branch_count++; break; case 0xFF: // not yet supported break; } } cs_free(insn, count); }