11#!/usr/bin/env python
22
33# Convert an ESP 32 OTA partition into an ELF
4-
4+ import sys
5+ import json
56import os , argparse
67from makeelf .elf import *
78from esptool import *
89from esp32_firmware_reader import *
10+ from read_nvs import *
911
1012def image_base_name (path ):
1113 filename_w_ext = os .path .basename (path )
@@ -133,7 +135,7 @@ def image2elf(filename, output_file, verbose=False):
133135 segments = {
134136 '.flash.rodata' : 'rw' ,
135137 '.dram0.data' : 'rw' ,
136- '.iram0.vectors' : 'rx ' ,
138+ '.iram0.vectors' : 'rwx ' ,
137139 '.flash.text' : 'rx'
138140 }
139141
@@ -206,12 +208,17 @@ def flash_dump_to_elf(filename, partition):
206208 fh .close ()
207209 return part_table
208210
211+ def dump_partition (fh , part_name , offset , size , dump_file ):
212+ print ("Dumping partition '" + part_name + "' to " + dump_file )
213+ dump_bytes (fh , offset , size , dump_file )
214+
209215def main ():
210216 desc = 'ESP32 Firmware Image Parser Utility'
211217 arg_parser = argparse .ArgumentParser (description = desc )
212- arg_parser .add_argument ('action' , choices = ['show_partitions' , 'dump_partition' , 'create_elf' ], help = 'Action to take' )
218+ arg_parser .add_argument ('action' , choices = ['show_partitions' , 'dump_partition' , 'create_elf' , 'dump_nvs' ], help = 'Action to take' )
213219 arg_parser .add_argument ('input' , help = 'Firmware image input file' )
214220 arg_parser .add_argument ('-output' , help = 'Output file name' )
221+ arg_parser .add_argument ('-nvs_output_type' , help = 'output type for nvs dump' , type = str , choices = ["text" ,"json" ], default = "text" )
215222 arg_parser .add_argument ('-partition' , help = 'Partition name (e.g. ota_0)' )
216223 arg_parser .add_argument ('-v' , default = False , help = 'Verbose output' , action = 'store_true' )
217224
@@ -226,7 +233,11 @@ def main():
226233 # parse that ish
227234 part_table = read_partition_table (fh , verbose )
228235
229- if args .action in ['dump_partition' , 'create_elf' ]:
236+ if args .action in ['dump_partition' , 'create_elf' , 'dump_nvs' ]:
237+ if (args .partition is None ):
238+ print ("Need partition name" )
239+ return
240+
230241 part_name = args .partition
231242
232243 if args .action == 'dump_partition' and args .output is not None :
@@ -235,10 +246,10 @@ def main():
235246 dump_file = part_name + '_out.bin'
236247
237248 if part_name in part_table :
238- print ("Dumping partition '" + part_name + "' to " + dump_file )
239249 part = part_table [part_name ]
240- dump_bytes (fh , part ['offset' ], part ['size' ], dump_file ) # dump_file will be written out
241250
251+ if args .action == 'dump_partition' :
252+ dump_partition (fh , part_name , part ['offset' ], part ['size' ], dump_file )
242253 if args .action == 'create_elf' :
243254 # can only generate elf from 'app' partition type
244255 if part ['type' ] != 0 :
@@ -247,9 +258,22 @@ def main():
247258 if args .output is None :
248259 print ("Need output file name" )
249260 else :
261+ dump_partition (fh , part_name , part ['offset' ], part ['size' ], dump_file )
250262 # we have to load from a file
251263 output_file = args .output
252264 image2elf (dump_file , output_file , verbose )
265+ elif args .action == 'dump_nvs' :
266+ if part ['type' ] != 1 or part ['subtype' ] != 2 : # Wifi NVS partition (4 is for encryption key)
267+ print ("Uh oh... bad partition type. Can only dump NVS partition type." )
268+ else :
269+ dump_partition (fh , part_name , part ['offset' ], part ['size' ], dump_file )
270+ with open (dump_file , 'rb' ) as fh :
271+ if (args .nvs_output_type != "text" ):
272+ sys .stdout = open (os .devnull , 'w' ) # block print()
273+ pages = read_nvs_pages (fh )
274+ sys .stdout = sys .stdout = sys .__stdout__ # re-enable print()
275+ if (args .nvs_output_type == "json" ):
276+ print (json .dumps (pages ))
253277 else :
254278 print ("Partition '" + part_name + "' not found." )
255279
0 commit comments