def load_ram(esp, args): if(esp.CHIP_NAME == 'ESP32'): image = esptool.LoadFirmwareImage("esp32", args.filename) else: image = esptool.LoadFirmwareImage("esp8266", args.filename) if(DEBUG): print('RAM boot...') for seg in image.segments: offset = seg.addr data = seg.data size = seg.file_offs if(DEBUG): print('Downloading %d bytes at %08x...' % (size, offset)) sys.stdout.flush() esp.mem_begin(size, esptool.div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, offset) seq = 0 while len(data) > 0: esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) data = data[esp.ESP_RAM_BLOCK:] seq += 1 if(DEBUG): print('done!') if(DEBUG): print('All segments done, executing at %08x' % image.entrypoint) try: esp.mem_finish(image.entrypoint) except: #print "error but ignore" pass
def test_elf_section_header_not_at_end(self): self.run_elf2image("esp8266", self.ELF) image = esptool.LoadFirmwareImage("esp8266", self.BIN_LOAD) self.assertEqual(3, len(image.segments)) self.assertImageContainsSection(image, self.ELF, ".data") self.assertImageContainsSection(image, self.ELF, ".text") self.assertImageContainsSection(image, self.ELF, ".rodata")
def _test_elf2image(self, elfpath, binpath): try: self.run_elf2image("esp8266", elfpath, 2) image = esptool.LoadFirmwareImage("esp8266", binpath) self.assertEqual(4, len(image.segments)) self.assertImageContainsSection(image, elfpath, ".data") self.assertImageContainsSection(image, elfpath, ".text") self.assertImageContainsSection(image, elfpath, ".rodata") irom_segment = image.segments[0] self.assertEqual(0, irom_segment.addr, "IROM segment 'load address' should be zero") with open(elfpath, "rb") as f: e = ELFFile(f) sh_size = (e.get_section_by_name(".irom0.text").header.sh_size + 15) & ~15 self.assertEqual( len(irom_segment.data), sh_size, "irom segment (0x%x) should be same size (16 padded) as .irom0.text section (0x%x)" % (len(irom_segment.data), sh_size)) # check V2 CRC (for ESP8266 SDK bootloader) with open(binpath, "rb") as f: f.seek(-4, os.SEEK_END) image_len = f.tell() crc_stored = struct.unpack("<I", f.read(4))[0] f.seek(0) crc_calc = esptool.esp8266_crc32(f.read(image_len)) self.assertEqual(crc_stored, crc_calc) # test imageinfo doesn't fail self.assertImageInfo(binpath) finally: try_delete(binpath)
def _test_elf2image(self, elfpath, binpath, extra_args=[]): try: self.run_elf2image("esp32", elfpath, extra_args=extra_args) image = esptool.LoadFirmwareImage("esp32", binpath) self.assertImageInfo(binpath, "esp32") return image finally: try_delete(binpath)
def test_loaded_sections(self): image = esptool.LoadFirmwareImage("esp8266", self.BIN_LOAD) # Adjacent sections are now merged, len(image.segments) should # equal 2 (instead of 3). self.assertEqual(2, len(image.segments)) self.assertImageContainsSection(image, self.ELF, ".data") self.assertImageContainsSection(image, self.ELF, ".text") # Section .rodata is merged in the binary with the previous one, # so it won't be found in the binary image. self.assertImageDoesNotContainSection(image, self.ELF, ".rodata")
def load_ram(esp, args, esprftool): esprftool._SignalTX.emit('load begin') if (esp.CHIP_NAME == 'ESP32'): image = esptool.LoadFirmwareImage("esp32", args.filename) else: image = esptool.LoadFirmwareImage("esp8266", args.filename) image_size = os.path.getsize(args.filename) send_size = 0 #print('RAM boot...') for seg in image.segments: offset = seg.addr data = seg.data size = seg.file_offs sys.stdout.flush() esp.mem_begin(size, esptool.div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, offset) seq = 0 while len(data) > 0: esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) data = data[esp.ESP_RAM_BLOCK:] seq += 1 if len(data) < esp.ESP_RAM_BLOCK: send_size += len(data) else: send_size += esp.ESP_RAM_BLOCK esprftool._Signalprb.emit(100 * send_size // image_size) #print('done!') print('All segments done, executing at %08x' % image.entrypoint) try: esp.mem_finish(image.entrypoint) except: #print "error but ignore" pass esprftool._SignalTX.emit('load bin success') esp._port.close() esprftool._Signalprb.emit(100)
def test_binary_patched(self): self.run_elf2image("esp32", self.ELF, extra_args=["--elf-sha256-offset", "32"]) image = esptool.LoadFirmwareImage("esp32", self.BIN) rodata_segment = image.segments[0] observed_sha256 = rodata_segment.data[0:32] sha256 = hashlib.sha256() with open(self.ELF, "rb") as f: f.seek(0, os.SEEK_END) size = f.tell() f.seek(0, 0) sha256.update(f.read(size)) expected_sha256 = sha256.digest() self.assertSequenceEqual(expected_sha256, observed_sha256)
def test_binary_patched(self): self.run_elf2image( "esp32", self.ELF, extra_args=["--elf-sha256-offset", "0x%x" % self.SHA_OFFS]) image = esptool.LoadFirmwareImage("esp32", self.BIN) rodata_segment = image.segments[0] observed_sha256 = rodata_segment.data[ self.SHA_OFFS - 0x20:self.SHA_OFFS - 0x20 + 32] # subtract 0x20 byte header here with open(self.ELF, "rb") as f: expected_sha256 = hashlib.sha256(f.read()).digest() self.assertSequenceEqual(expected_sha256, observed_sha256)
def image_info(chip, filename): finfo = open("{}.info".format(filename), "wt+") image = esptool.LoadFirmwareImage(chip, filename) print('Image version: %d' % image.version) print('Entry point: %08x' % image.entrypoint if image.entrypoint != 0 else 'Entry point not set') print("secure_pad: {}".format(image.secure_pad)) print("flash_mode: {}".format(image.flash_mode)) print("flash_size_freq: {}".format(image.flash_size_freq)) finfo.write("0x{:x}\n".format(image.entrypoint)) finfo.write("{}\n".format(len(image.segments))) finfo.write("{} {} {} \n".format(image.secure_pad, image.flash_mode, image.flash_size_freq)) print('%d segments' % len(image.segments)) print() idx = 0 for seg in image.segments: idx += 1 print('Segment %d: %r' % (idx, seg)) print(" addr=0x{:x} file_offs=0x{:x} include_in_checksum={}\n".format( seg.addr, seg.file_offs, seg.include_in_checksum)) fsegname = "{}.seg{}".format(filename, idx) with open(fsegname, "wb+") as file: file.write(seg.data) finfo.write("{} {} 0x{:x} 0x{:x} {}\n".format(idx, fsegname, seg.addr, seg.file_offs, seg.include_in_checksum)) calc_checksum = image.calculate_checksum() print('Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == calc_checksum else 'invalid - calculated %02x' % calc_checksum)) try: digest_msg = 'Not appended' if image.append_digest: is_valid = image.stored_digest == image.calc_digest digest_msg = "%s (%s)" % (hexify( image.calc_digest).lower(), "valid" if is_valid else "invalid") print('Validation Hash: %s' % digest_msg) except AttributeError: pass # ESP8266 image has no append_digest field finfo.close() print("END")
def test_binary_patched(self): try: self.run_elf2image("esp32", self.ELF, extra_args=["--elf-sha256-offset", "0x%x" % self.SHA_OFFS]) image = esptool.LoadFirmwareImage("esp32", self.BIN) rodata_segment = image.segments[0] bin_sha256 = rodata_segment.data[self.SHA_OFFS - 0x20: self.SHA_OFFS - 0x20 + 32] # subtract 0x20 byte header here with open(self.ELF, "rb") as f: elf_computed_sha256 = hashlib.sha256(f.read()).digest() with open(self.BIN, "rb") as f: f.seek(self.SHA_OFFS) bin_sha256_raw = f.read(len(elf_computed_sha256)) self.assertSequenceEqual(elf_computed_sha256, bin_sha256) self.assertSequenceEqual(elf_computed_sha256, bin_sha256_raw) finally: try_delete(self.BIN)
def _test_elf2image(self, elfpath, binpath): try: self.run_elf2image("esp8266", elfpath, 2) image = esptool.LoadFirmwareImage("esp8266", binpath) self.assertEqual(4, len(image.segments)) self.assertImageContainsSection(image, elfpath, ".data") self.assertImageContainsSection(image, elfpath, ".text") self.assertImageContainsSection(image, elfpath, ".rodata") irom_segment = image.segments[0] self.assertEqual(0, irom_segment.addr, "IROM segment 'load address' should be zero") with open(elfpath, "rb") as f: e = ELFFile(f) sh_size = (e.get_section_by_name(".irom0.text").header.sh_size + 3) & ~3 self.assertEqual(len(irom_segment.data), sh_size, "irom segment (0x%x) should be same size as .irom0.text section (0x%x)" % (len(irom_segment.data), sh_size)) # test imageinfo doesn't fail self.assertImageInfo(binpath) finally: try_delete(binpath)
def test_loaded_sections(self): image = esptool.LoadFirmwareImage("esp8266", self.BIN_LOAD) self.assertEqual(3, len(image.segments)) self.assertImageContainsSection(image, self.ELF, ".data") self.assertImageContainsSection(image, self.ELF, ".text") self.assertImageContainsSection(image, self.ELF, ".rodata")
#!/usr/bin/env python3 # https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map import sys # sys.path.append("/home/user/.local/bin/esptool.py") # `which esptool.py` from esp_elf import XtensaElf, ElfSection import esptool if len(sys.argv) == 1: print( 'Usage: ./user_bin_to_elf.py user_app.bin\r\n\r\nThis tool will generate user_app.bin.elf' ) exit(1) image = esptool.LoadFirmwareImage("", sys.argv[1]) out_elf_file = sys.argv[1] + '.elf' elf = XtensaElf(out_elf_file, image.entrypoint) print('Image version: %d' % image.version) print('Entry point: 0x%08x' % image.entrypoint if image.entrypoint != 0 else 'Entry point not set') print('%d segments' % len(image.segments)) idx = 0 for seg in image.segments: idx += 1 seg_name = ", ".join([ seg_range[2] for seg_range in image.ROM_LOADER.MEMORY_MAP if seg_range[0] <= seg.addr < seg_range[1] ]) print('Segment %d: %r [%s]' % (idx, seg, seg_name)) elf_section = ElfSection(seg_name, seg.addr, seg.data, seg_name[0] == 'I')