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;
}
Example #2
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);

	
}