def mkdirs(dir_path): try: if not pe(dir_path): os.makedirs(dir_path) except Exception as ex: if type(ex) is not FileExistsError: raise ex return dir_path
def elfmanip(self, inpath, outpath): # {{{ t1 = timer() retcode = 0 self.p('\nRunning ELF Manipulator') flags = [ '-R', '-M', '-r', # remove '.rodata.trace', # firmware F3 trace section '-r', # '.rodata.fw_trace', # new name for firmware F3 trace section '-c', self.core_root, ] if self.coproc_path is not None and pe(self.coproc_path): flags.extend(['-s', self.coproc_path]) retcode, stdout, stderr = self.call( [ self.python, '-O', pj(self.mypspath, 'elfManipulator', 'elfManipulator.py'), ] + flags + [ inpath, outpath, ] ) if retcode != 0: self.p('ELF Manipulator failed. Logs below:') self.p('stdout: %s' % stdout) self.p('stderr: %s' % stderr) else: self.log('ELF Manipulator logs:') self.log('stdout: %s' % stdout) self.log('stderr: %s' % stderr) t2 = timer() t_diff = t2 - t1 self.p(' ELF Manipulator execution time: %s' % t_str(t_diff)) return retcode
def finalize_dst(self): # {{{ if self.outpath is not None: # {{{ if pe(self.outpath): self.p( 'Warning: output ELF already exists at %s, overwriting' % ( self.outpath ) ) os.unlink(self.outpath) if not self.debug: # Remove all manipulated ELF files, except the last one. Move that to # the final destination path = [self.elfpath] for manip in self.executed_manips[0:-1]: path.append(manip) os.unlink('.'.join(path)) shutil.move( '.'.join([self.elfpath] + self.executed_manips), self.outpath, ) else: shutil.copyfile( '.'.join([self.elfpath] + self.executed_manips), self.outpath, ) self.elfpath = self.outpath self.executed_manips = [] # }}} else: self.p('Warning: nothing to finalize, since there is no output') self.finalized = True
def main(): # Use optparse to set up usage use = "Usage: python %prog <Output ELF> <Output string database File> <Input ELF> <input pickle file> <CompactType: Intermediate or Final>" parser = optparse.OptionParser(usage = use, version="%prog 1.0") options, arguments = parser.parse_args() # Check arguments if len(arguments) != 5: parser.error("Unexpected argument length") print "Unexpected argument length" exit(1) baseELF = arguments[2] if not pe(baseELF): parser.error("Specified ELF file does not exist.") print "Specified ELF file does not exist." exit(1) #just call the function with all arguments diag_msg_compact_modify_elf(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]) #print out the database print diagStringDatabase exit(0)
def main(): # Use optparse to set up usage use = "Usage: python %prog [options] <Input ELF> <Output ELF>" use += "\n python %prog -s symbolName <ELF>" parser = optparse.OptionParser(usage=use, version="%prog 1.11") parser.add_option("-d", action="store_true", dest="debug", help="enable debug") parser.add_option("-r", action="store", dest="removeSection", type="str", help="Section to remove") parser.add_option("-t", action="store_true", dest="timing", help="print program execution time") parser.add_option("-V", action="store_true", dest="verification", help="enable ELF verification (currently none)") parser.add_option("-R", action="store_true", dest="ro_fatal", help="Enable ro fatal section removal/compression") parser.add_option("-M", action="store_true", dest="overlay_mem_dump", help="Enable memory dump overlay") parser.add_option("-c", action="store", dest="compressorRoot", help="Specify the root folder of the Q6Zip compressor") parser.add_option("-s", action="store", dest="coprocMerge", type="str", help="Path of coprocessor (silver) ELF") options, arguments = parser.parse_args() # Check arguments if len(arguments) != 2: parser.error("Unexpected argument length") exit(const.RC_ERROR) baseELF = arguments[0] modifiedELF = arguments[1] if not pe(baseELF): parser.error("Specified ELF file does not exist.") exit(const.RC_ERROR) # Print configuration if not options.debug: print "================================================================" print " elfManipulator.py - Generic manipulator for ELF files" print "----------------------------------------------------------------" print " Base ELF: ".ljust(20) + baseELF print " Modified ELF: ".ljust(20) + modifiedELF print " Debug: ".ljust(20) + str(options.debug) print " Verification: ".ljust(20) + str(options.verification) print "================================================================" # Record the starting time if options.timing: start_time = time.time() # Get the elf file as an elfFile object if not options.debug: print "----------------------------------------------------------------" print " Getting ELF data from input ELF..." print "----------------------------------------------------------------" elf = elfFileClass.elfFile(baseELF) # If debug is enabled, show ELF contents similarly to readelf -a if options.debug: elf.printInfo() if not options.debug: print "----------------------------------------------------------------" print " Applying requested ELF modifications..." print "----------------------------------------------------------------" """ HERE IS WHERE ALL THE ELF MODIFICATIONS SHOULD HAPPEN """ # -r option: Remove specified section if options.removeSection: if not options.debug: print "Attempting to remove section '" + options.removeSection + "'" elf.removeSectionByName(options.removeSection) symbolDict = {} # -M option: Remove BSS section for 'overlay_mem_dump' feature overlay_mem_dumpSize = -1 if options.overlay_mem_dump: print "OVERLAY_MEM_DUMP" overlay_mem_dumpSh = elf.getSectionByName("overlay_mem_dump") ro_fatalSh = elf.getSectionByName("ro_fatal") if overlay_mem_dumpSh != const.RC_ERROR and ro_fatalSh != const.RC_ERROR: # If an overlay_mem_dump section is found print "\t'overlay_mem_dump' section found" print "\tAttempting to remove 'overlay_mem_dump' BSS section." overlay_mem_dumpSize = overlay_mem_dumpSh.sh_size elf.removeBssOverlaySectionByName("overlay_mem_dump") if overlay_mem_dumpSize > ro_fatalSh.sh_size: # It is expected that size of ro_fatal section matches the # program segment size in subsequent steps. elfManipulator is # currently written to manipulate single section segments, # with the EXCEPTION of removing BSS sections. print "\t'overlay_mem_dump' exceeded 'ro_fatal' size. Re-sizing." elf.resizeSectionByName("ro_fatal", len(ro_fatalSh.contents)) else: if overlay_mem_dumpSh == const.RC_ERROR: print "\tNo 'overlay_mem_dump' section found. No-op." if ro_fatalSh == const.RC_ERROR: print "\tNo 'ro_fatal' section found. No-op." # -R option: Remove or compress 'ro_fatal' section if options.ro_fatal: print print "RO_FATAL COMPRESSION" # Get the section in question sh = elf.getSectionByName("ro_fatal") if sh != const.RC_ERROR: # If an ro_fatal section is found print "\t'ro_fatal' section found" if sh.sh_size == 0: # If 0 size section is found, remove the section for mbn print "\tZero-sized 'ro_fatal' section. Attempting removal." elf.removeSectionByName("ro_fatal") else: # Move up the ro_fatal section and then compress it print "\tMoving up 'ro_fatal' to closest section" symbolDict["__ro_fatal_old_start"] = sh.sh_addr oldSize = sh.sh_size elf.moveupSectionByName("ro_fatal") print "\tCompressing 'ro_fatal' contents using zlib" sh = elf.compressSectionByName("ro_fatal") if (sh != const.RC_ERROR): # If compression is successful, update symbols accordingly symbolDict["__ro_fatal_new_start"] = sh.sh_addr symbolDict["__ro_fatal_new_end"] = sh.sh_addr + len( sh.contents) else: utils.raiseElfManipulatorError( "Failed to compress ro_fatal") # Print out statistics print "\tOld Size: " + str(oldSize) print "\tNew Size: " + str(sh.sh_size) else: # The last segment is still created due to linker script print "\tNo 'ro_fatal' section found, checking for zero-sized segment" if ((elf.programHeaderTable[-1].p_memsz == 0) and (elf.programHeaderTable[-1].p_vaddr == 0)): print "\tRemoving zero-sized segment" elf.elfHeader.e_phnum -= 1 elf.programHeaderTable.pop() #============================================= # START: Q6_ZIP CHANGES #============================================= q6_roSection = ".candidate_compress_section" q6_rwSection = ".rw_candidate_compress_section" pageSize = 4096 # determine where the compressors reside my_d = ps(inspect.getframeinfo(inspect.currentframe()).filename)[0] compressorDirs = [ ap(pj(my_d, "../../core/kernel/dlpager/compressor")), ap(pj(my_d, "../../../core/kernel/dlpager/compressor")), ap(pj(my_d, "./include")), ] if options.compressorRoot: compressorDirs.insert(0, options.compressorRoot) for d in compressorDirs: if os.path.isdir(d) and 'q6zip_compress.py' in os.listdir(d): sys.path.insert(0, d) break print print "Q6ZIP FEATURE (RO)" # Get the ELF section containing the code to compress sh = elf.getSectionByName(q6_roSection) # Check if the section exists if (sh != const.RC_ERROR): # Save the old VA before ANY modifications to the section/segment oldVA = sh.sh_addr # Save old size oldSize = sh.sh_size print "oldVA = " + hex(oldVA) print "Size of " + q6_roSection + " is " + str(sh.sh_size) symbolDict["start_va_uncompressed_text"] = sh.sh_addr symbolDict["end_va_uncompressed_text"] = sh.sh_addr + sh.sh_size # Move up the vaddr of the section, corresponding segment and mark all # its symbols as SHN_UNDEF. Will fail if q6_roSection is part of multi- # section segment in the ELF. # Save the new VA after moving up the section/segment print "Moving up " + q6_roSection + " to closest segment" elf.moveupSectionByName(q6_roSection) newVA = sh.sh_addr print "newVA = " + hex(newVA) print "Compress " + q6_roSection import q6zip_compress try: text_nonpartial_start = elf.getSymbolByName( "__swapped_range_text_partial_end__").st_value if text_nonpartial_start != 0: size_partial = text_nonpartial_start - oldVA print "text nonpartial start = " + hex(text_nonpartial_start) print "text partial size = " + str(size_partial) sh.contents = q6zip_compress.compress(pageSize, newVA, sh.contents, size_partial) except: sh.contents = q6zip_compress.compress(pageSize, newVA, sh.contents) # Alignment needed for Q6ZIP RW in the next section alignedSize = pageSize * (len(sh.contents) / pageSize + 1) for i in xrange(alignedSize - len(sh.contents)): sh.contents += '\0' elf.resizeSectionByName(q6_roSection, alignedSize) print "Size of " + q6_roSection + " after compression " + str( sh.sh_size) print("Memory Savings Report: Q6Zip RO: Gross Memory Saved: %u\n" % (oldSize - sh.sh_size)) symbolDict["start_va_compressed_text"] = newVA symbolDict["end_va_compressed_text"] = sh.sh_addr + sh.sh_size # Change permissions (remove execute) print "\tRemoving X from " + q6_roSection sh.sh_flags = sh.sh_flags & ~const.sectionFlags.SHF_EXECINSTR ph = elf.getProgramHeaderBySectionName(q6_roSection) if ph != const.RC_ERROR: ph.p_flags &= ~const.segmentFlags.PF_X else: utils.raiseElfManipulatorError( "Unexpected error while changing permissions for " + q6_roSection) if (sh != const.RC_ERROR): print "Success compressing " + q6_roSection else: utils.raiseElfManipulatorError("Failed to compress " + q6_roSection) else: # Like ro_fatal, need to check for zero-sized segment print "No " + q6_roSection + " section found, checking for zero-sized segment" if ((elf.programHeaderTable[-1].p_memsz == 0) and (elf.programHeaderTable[-1].p_vaddr == 0)): print "Removing zero-sized segment" elf.elfHeader.e_phnum -= 1 elf.programHeaderTable.pop() print print "Q6ZIP FEATURE (RW)" # Get the ELF section containing the code to compress sh = elf.getSectionByName(q6_rwSection) # Check if the section exists if (sh != const.RC_ERROR): print "\t'" + q6_rwSection + " section found" print "Size of " + q6_rwSection + " is " + str(sh.sh_size) # Save the old VA before ANY modifications to the section/segment oldSize = sh.sh_size bss_common_start = elf.getSymbolByName( "__swapped_segments_bss_start__").st_value print "\bss_common_start = " + hex(bss_common_start) symbolDict["start_va_uncompressed_rw"] = sh.sh_addr symbolDict["end_va_uncompressed_rw"] = sh.sh_addr + sh.sh_size rw_contents = bss_common_start - sh.sh_addr print "\t rw_contents = " + hex(rw_contents) # Move up the section print "\tMoving up " + q6_rwSection + " to closest section" elf.moveupSectionByName(q6_rwSection) newVA = sh.sh_addr print "\tCompressing " + q6_rwSection + " contents using q6 compressor" import rw_py_compress sh.contents = rw_py_compress.rw_py_compress(pageSize, newVA, sh.contents[0:rw_contents]) #pad with 0s till pageSize rem = len(sh.contents) % pageSize if rem != 0: sh.contents = sh.contents.ljust( len(sh.contents) + pageSize - rem, '0') # Resize the section elf.resizeSectionByName(q6_rwSection, len(sh.contents)) symbolDict["start_va_compressed_rw"] = newVA symbolDict["end_va_compressed_rw"] = sh.sh_addr + sh.sh_size # Change permissions (remove execute) print "\tRemoving X from " + q6_rwSection sh.sh_flags = sh.sh_flags & ~const.sectionFlags.SHF_EXECINSTR ph = elf.getProgramHeaderBySectionName(q6_rwSection) if ph != const.RC_ERROR: ph.p_flags &= ~const.segmentFlags.PF_X else: utils.raiseElfManipulatorError( "Unexpected error while changing permissions for " + q6_rwSection) # Print out statistics print "Size of " + q6_rwSection + " after compression " + str( sh.sh_size) print("Memory Savings Report: Q6Zip RW: Gross Memory Saved: %u" % (oldSize - sh.sh_size)) # Moving up sections elf.moveupElfOffsetSectionByName(q6_roSection) elf.moveupElfOffsetSectionByName(q6_rwSection) # moving this part to pplkcmd.py for prototyping. #elf.moveupElfOffsetSectionByName(dynrec_section) #elf.moveupElfOffsetSectionByName("QSR_STRING") else: # Like ro_fatal, need to check for zero-sized segment print "\tNo " + q6_rwSection + " section found, checking for zero-sized segment" if ((elf.programHeaderTable[-1].p_memsz == 0) and (elf.programHeaderTable[-1].p_vaddr == 0)): print "\tRemoving zero-sized segment" elf.elfHeader.e_phnum -= 1 elf.programHeaderTable.pop() #============================================= # END: Q6_ZIP CHANGES #============================================= # -M option: Remove BSS section for 'overlay_mem_dump' feature if options.overlay_mem_dump and overlay_mem_dumpSize >= 0: # Need to check that the overlay_memdump does not exceed ro_fatal + # candidate_compress_section AFTER manipulations. roFatalSh = elf.getSectionByName("ro_fatal") roCompressSh = elf.getSectionByName(q6_roSection) rwCompressSh = elf.getSectionByName(q6_rwSection) roFatalSz = 0 roCompressSz = 0 rwCompressSz = 0 if roFatalSh != const.RC_ERROR: roFatalSz = roFatalSh.sh_size if roCompressSh != const.RC_ERROR: roCompressSz = roCompressSh.sh_size if rwCompressSh != const.RC_ERROR: rwCompressSz = rwCompressSh.sh_size if overlay_mem_dumpSize > (roFatalSz + roCompressSz + rwCompressSz): print "FATAL ERROR: memdump exceeds ro_fatal + ro/rw candidate_compress_sections." print "ro_fatal size: %s bytes" % str(roFatalSz) print "ro candidate_compress_section size: %s bytes" % str( roCompressSz) print "rw candidate_compress_section size: %s bytes" % str( rwCompressSz) print "FW memdump overlay size: %s bytes" % str( overlay_mem_dumpSize) print "Short by: %s bytes" % ( (roFatalSz + roCompressSz + rwCompressSz) - overlay_mem_dumpSize) print "Aborting" exit(const.RC_ERROR) # After all modifications, update image_vend pointing to the end of the # last program segment, aligned using integer division lastPh = elf.programHeaderTable[-1] for ph in elf.programHeaderTable: if ph.p_vaddr > lastPh.p_vaddr: lastPh = ph endAddress = lastPh.p_vaddr + lastPh.p_align * ( lastPh.p_memsz / lastPh.p_align + 1) symbolDict["image_vend"] = endAddress #=========================================================================== # Option: -s <COPROC_ELF> # Description: Combine silver coprocessor image with primary ELF. No debug # information will be preserved. # Requirements: # [1] Coprocessor image only has a single segment # [2] Primary image has a single section segment (COPROC_IMAGE) # [3] Coprocessor segment does not exceed the original size of COPROC_IMAGE # [4] Coprocessor segment contents becomes the contents of COPROC_IMAGE # [5] __coproc_image_start__ must point to the start of the section #=========================================================================== if options.coprocMerge: print "Combining coprocessor image with primary image..." # Ensure that coprocessor segment does not exceed COPROC_IMAGE size coproc_imageSh = elf.getSectionByName("COPROC_IMAGE") coproc_imagePh = elf.getProgramHeaderBySectionName("COPROC_IMAGE") coproc_align = 256 * (1 << 10) print "\tLooking for COPROC_IMAGE section in primary image" if coproc_imageSh != const.RC_ERROR and coproc_imagePh != const.RC_ERROR: print "\tCOPROC_IMAGE section found in primary image" print "\tValidating coprocessor ELF" coprocELF = options.coprocMerge # Read in the coprocessor ELF and verify [1] coproc = elfFileClass.elfFile(coprocELF) if len(coproc.programHeaderTable) != 1: utils.raiseElfManipulatorError( "Coproc image has more than 1 segment") print "\tComparing size of coprocessor image with reserved COPROC_IMAGE" if coproc_imagePh.p_filesz >= coproc.programHeaderTable[0].p_filesz: # Move up COPROC_IMAGE, if required (both VA/PA and ELF offsets) print "\tMoving up COPROC_IMAGE (address and ELF offset)" elf.moveupSectionByName("COPROC_IMAGE", align=coproc_align) elf.moveupElfOffsetSectionByName("COPROC_IMAGE") # Read in the coprocessor image coprocImage = utils.getDataFromELF( coprocELF, coproc.programHeaderTable[0].p_offset, coproc.programHeaderTable[0].p_filesz) # Replace the contents of COPROC_IMAGE print "\tReplacing contents of COPROC_IMAGE and resizing" coproc_imageSh.contents = coprocImage coprocFinalSize = coproc_imagePh.p_align * ( len(coproc_imageSh.contents) / coproc_imagePh.p_align + 1) for i in xrange(coprocFinalSize - len(coproc_imageSh.contents)): coproc_imageSh.contents += '\0' elf.resizeSectionByName("COPROC_IMAGE", len(coproc_imageSh.contents)) print "\tUpdating __coproc_image_start__" symbolDict["__coproc_image_start__"] = coproc_imagePh.p_vaddr symbolDict["fw_coproc_image_start"] = coproc_imagePh.p_vaddr print "\tUpdating MMU entries surrounding the coprocessor" symbolDict[ "__MMU_region_unmapped_align_padding_start_coproc"] = coproc_imagePh.p_vaddr coproc_end = coproc_imagePh.p_vaddr + len( coproc_imageSh.contents) coproc_end = (coproc_end + coproc_imagePh.p_align - 1) & ~(coproc_imagePh.p_align - 1) symbolDict[ "__MMU_region_start_name_qsr_A0_1_R_1_W_1_X_0_lock_1"] = coproc_end # move this step to pplkcmd.py for CR800980. #print "\tMoving up QSR_STRING" #elf.moveupElfOffsetSectionByName("QSR_STRING") else: # If coprocessor segment exists but is larger than reserved size, need to catch this immediately utils.raiseElfManipulatorError( "Coprocessor segment > COPROC_IMAGE") else: print "\tPrimary image does not have COPROC_IMAGE (no-op)" # Update all symbols if symbolDict: print "----------------------------------------------------------------" print " Updating symbol values from all ELF modifications..." print "----------------------------------------------------------------" elf.updateSymbolValuesByDict(symbolDict) # If verification is enabled, enable verification on if options.verification: print "----------------------------------------------------------------" print " Verifying modified ELF data..." print "----------------------------------------------------------------" elf.verify() # Write out the ELF file based on the elfFile object if not options.debug: print "----------------------------------------------------------------" print " Writing out modified ELF..." print "----------------------------------------------------------------" elf.writeOutELF(modifiedELF) # Record the starting time if options.timing: print("Execution time: %.2f seconds" % (time.time() - start_time)) # elfManipulator ran to completed, exit with return code 0 exit(const.RC_SUCCESS)