def decode_funcname(self, address): # Go over all DIEs in the DWARF information, looking for a subprogram # entry with an address range that includes the given address. Note that # this simplifies things by disregarding subprograms that may have # split address ranges. for CU in self.dwarfinfo.iter_CUs(): for DIE in CU.iter_DIEs(): try: if DIE.tag == 'DW_TAG_subprogram': lowpc = DIE.attributes['DW_AT_low_pc'].value # DWARF v4 in section 2.17 describes how to interpret the # DW_AT_high_pc attribute based on the class of its form. # For class 'address' it's taken as an absolute address # (similarly to DW_AT_low_pc); for class 'constant', it's # an offset from DW_AT_low_pc. highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) continue if lowpc <= address <= highpc: return DIE.attributes['DW_AT_name'].value except KeyError: continue return None
def __init_functions(self): for CU in self._dwarffile.iter_CUs(): for DIE in CU.iter_DIEs(): try: if DIE.tag == 'DW_TAG_subprogram': lowpc = DIE.attributes['DW_AT_low_pc'].value # DWARF v4 in section 2.17 describes how to interpret the # DW_AT_high_pc attribute based on the class of its form. # For class 'address' it's taken as an absolute address # (similarly to DW_AT_low_pc); for class 'constant', it's # an offset from DW_AT_low_pc. highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) continue self.functions[DIE.attributes['DW_AT_name'].value] = self._process.memory[self._module.base + lowpc - self.base_address : self._module.base + highpc - self.base_address] except KeyError: continue
def parse_dwarf(dwarfinfo): if should_log: print("") print("Building DWARF lookup table...") templist = [] for CU in dwarfinfo.iter_CUs(): for DIE in CU.iter_DIEs(): try: # Using each DIE (Debugging Information Entry), the lower and # upper bounds of a function (subprogram) are recorded. This # takes into account entries that may only have a length instead # of an upper-bound attribute if DIE.tag == 'DW_TAG_subprogram': lowpc = DIE.attributes['DW_AT_low_pc'].value highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: highpc = 0 namestring = bytes2str(DIE.attributes['DW_AT_name'].value) if lowpc > 0: templist.append( FuncNode(lowpc=lowpc, highpc=highpc, namestring=namestring)) except KeyError: continue if should_log: for temp in templist: print(temp.namestring + ": " + str(temp.lowpc) + "/" + str(temp.highpc)) return sorted(templist, key=lambda x: x.lowpc)
def get_die_mapped_address(die, parser, dwarfinfo): """Get the bounding addresses from a DIE variable or subprogram""" low = None high = None if die.tag == "DW_TAG_variable": if "DW_AT_location" in die.attributes: loc_attr = die.attributes["DW_AT_location"] if parser.attribute_has_location(loc_attr, die.cu["version"]): loc = parser.parse_from_attribute(loc_attr, die.cu["version"]) if isinstance(loc, LocationExpr): addr = describe_DWARF_expr(loc.loc_expr, dwarfinfo.structs) matcher = DT_LOCATION.match(addr) if matcher: low = int(matcher.group(1), 16) high = low + 1 if die.tag == "DW_TAG_subprogram": if "DW_AT_low_pc" in die.attributes: low = die.attributes["DW_AT_low_pc"].value high_pc = die.attributes["DW_AT_high_pc"] high_pc_class = describe_form_class(high_pc.form) if high_pc_class == "address": high = high_pc.value elif high_pc_class == "constant": high = low + high_pc.value return low, high
def _decode_funcname(dwarfinfo, address): # Go over all DIEs in the DWARF information, looking for a subprogram # entry with an address range that includes the given address. Note that # this simplifies things by disregarding subprograms that may have # split address ranges. for CU in dwarfinfo.iter_CUs(): for DIE in CU.iter_DIEs(): try: if DIE.tag == 'DW_TAG_subprogram': lowpc = DIE.attributes['DW_AT_low_pc'].value # DWARF v4 in section 2.17 describes how to interpret the # DW_AT_high_pc attribute based on the class of its form. # For class 'address' it's taken as an absolute address # (similarly to DW_AT_low_pc); for class 'constant', it's # an offset from DW_AT_low_pc. highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) continue if lowpc <= address <= highpc: return DIE.attributes['DW_AT_name'].value except KeyError: continue return None
def __handle_DIE(DIE): # we are interested in two things: name and address range tag = DIE.tag attr = DIE.attributes # ignore compile unit info if tag == "DW_TAG_compile_unit": return None # check for low_pc lowpc = __extract_value(attr, "DW_AT_low_pc", -1) # we don't care if DIE holds no address if lowpc == -1: return None elif "DW_AT_high_pc" in attr.keys(): highpc_attr = attr["DW_AT_high_pc"] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == "address": highpc = highpc_attr.value elif highpc_attr_class == "constant": highpc = lowpc + highpc_attr.value else: highpc = lowpc # recursive search for name current_die = DIE while True: name = __extract_value(attr, "DW_AT_name", b"") if name and current_die.tag == "DW_TAG_subprogram": return {"name": name.decode(), "range": (lowpc, highpc)} origin = __extract_value(attr, "DW_AT_abstract_origin", -1) if origin == -1: break current_die = current_die.get_DIE_from_attribute( "DW_AT_abstract_origin") attr = current_die.attributes return None
def die_bounds(die): lowpc = die.attributes['DW_AT_low_pc'].value highpc_attr = die.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) highpc = highpc_attr.value if highpc_attr_class == 'address' else\ highpc_attr.value + lowpc if highpc_attr_class == 'constant' else\ Exception('Error: invalid DW_AT_high_pc class: %s' % highpc_attr_class) return lowpc, highpc
def get_source_info(self, address): """ returns the full path to the source file containing the code for the specified address, as well as the line number (1-based), and the function name (if in a function). :param address: requested address :type address: int :return: a tuple containing the source file path, the source file line (1-based) and the function name (None if not in a function) :rtype: tuple """ file_path, line, func_name = None, -1, None line = -1 func_name = None dwarf_info = self.get_dwarf_info() for CU in dwarf_info.iter_CUs(): try: line_program = dwarf_info.line_program_for_CU(CU) except DWARFError: continue if line_program is None: continue prev_state = None if line == -1: for entry in line_program.get_entries(): if entry.state is None: continue if prev_state and prev_state.address <= address < entry.state.address: file_path = CU.get_top_DIE().get_full_path() line = prev_state.line if entry.state.end_sequence: prev_state = None else: prev_state = entry.state if func_name is None: for DIE in CU.iter_DIEs(): try: if DIE.tag == 'DW_TAG_subprogram': low_pc = DIE.attributes['DW_AT_low_pc'].value high_pc_attr = DIE.attributes['DW_AT_high_pc'] high_pc_attr_class = describe_form_class(high_pc_attr.form) if high_pc_attr_class == 'address': high_pc = high_pc_attr.value elif high_pc_attr_class == 'constant': high_pc = low_pc + high_pc_attr.value else: continue if low_pc <= address < high_pc: func_name = DIE.attributes['DW_AT_name'].value.decode() break except KeyError: continue if func_name is not None: break return file_path, line - 1 if line != -1 else -1, func_name
def decode_funcname(dwarfinfo, address_start, address_end): # Go over all DIEs in the DWARF information, looking for a subprogram # entry with an address range that includes the given address. Note that # this simplifies things by disregarding subprograms that may have # split address ranges. func_l = [] l = [i for i in range(address_start, address_end)] for CU in dwarfinfo.iter_CUs(): for DIE in CU.iter_DIEs(): try: if DIE.tag == 'DW_TAG_subprogram': lowpc = DIE.attributes['DW_AT_low_pc'].value # DWARF v4 in section 2.17 describes how to interpret the # DW_AT_high_pc attribute based on the class of its form. # For class 'address' it's taken as an absolute address # (similarly to DW_AT_low_pc); for class 'constant', it's # an offset from DW_AT_low_pc. highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) continue #print ("--------------",hex(lowpc),hex(highpc)) if lowpc in l and highpc in l: #print ("oba") for address in range(lowpc, highpc): func_l.append( (address, DIE.attributes['DW_AT_name'].value)) elif lowpc not in l and highpc in l: #print ("HIGH") for address in range(address_start, highpc): func_l.append( (address, DIE.attributes['DW_AT_name'].value)) elif lowpc in l and highpc not in l: #print ("low") for address in range(lowpc, address_end): func_l.append( (address, DIE.attributes['DW_AT_name'].value)) else: pass for address in range(address_start, address_end): func_l.append( (address, DIE.attributes['DW_AT_name'].value)) print("Processing:", DIE.attributes['DW_AT_name'].value) except KeyError: continue return func_l
def add_to_funcdb(self, elf_file): # Create ELF file object elf = ELFFile(elf_file) # Get debug info dwarf_info = elf.get_dwarf_info() # Go over all compiler units (CU) for CU in dwarf_info.iter_CUs(): # Go over all debug information entries (DIE) in given CU for DIE in CU.iter_DIEs(): # We only care about subprogram if DIE.tag == 'DW_TAG_subprogram': if DIE.attributes.get('DW_AT_low_pc', None) is not None: low_pc = DIE.attributes['DW_AT_low_pc'].value if DIE.attributes.get('DW_AT_name', None) is not None: fxn_name = DIE.attributes['DW_AT_name'].value # DWARF v4 in section 2.17 describes how to interpret the # DW_AT_high_pc attribute based on the class of its form. # For class 'address' it's taken as an absolute address # (similarly to DW_AT_low_pc); for class 'constant', it's # an offset from DW_AT_low_pc. high_pc_attr = DIE.attributes['DW_AT_high_pc'] high_pc_attr_class = describe_form_class( high_pc_attr.form) if high_pc_attr_class == 'address': high_pc = high_pc_attr.value elif high_pc_attr_class == 'constant': high_pc = low_pc + high_pc_attr.value else: logger.error( 'Error: invalid DW_AT_high_pc class:', high_pc_attr_class) continue # Get file try: file_index = DIE.attributes[ 'DW_AT_decl_file'].value except KeyError: continue else: line_prog = dwarf_info.line_program_for_CU(CU) file = line_prog['file_entry'][file_index - 1].name # Get line line = DIE.attributes['DW_AT_decl_line'].value # Add to functionDB self.functionDB[(low_pc, high_pc)] = [ fxn_name, file, line ] # Print for debugging logger.debug("{}() @ {}:{}".format( fxn_name.decode("utf-8"), file.decode("utf-8"), line))
def get_die_size(die): if die.tag in [STR.DW_TAG_compile_unit, STR.DW_TAG_subprogram]: low_pc = die.attributes.get(STR.DW_AT_low_pc) high_pc = die.attributes.get(STR.DW_AT_high_pc) if low_pc is None or high_pc is None: raise Exception( "DW_AT_{low,high}_pc attr missing. Non-continuos code?") high_pc_form = descriptions.describe_form_class(high_pc.form) if high_pc_form == "constant": return high_pc.value elif high_pc_form == "address": return high_pc.value - low_pc.value else: raise Exception("Unknown attribute form {}".format(high_pc.form)) else: assert 0
def _parse_function_info(self, cu): for die in cu.iter_DIEs(): if die.tag != 'DW_TAG_subprogram': continue try: lowpc = die.attributes['DW_AT_low_pc'].value highpc_attr = die.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class(highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: logger.warn('invalid DW_AT_high_pc class: %s', highpc_attr_class) continue funcname = die.attributes['DW_AT_name'].value self._funcs.add(funcname, lowpc, highpc) except KeyError: continue
def _addr_in_DIE(self, DIE, address): if "DW_AT_ranges" in DIE.attributes: offset = DIE.attributes["DW_AT_ranges"].value range_lists = self.dwarff.range_lists() ranges = range_lists.get_range_list_at_offset(offset) for entry in ranges: # RangeEntry = (begin_offset, end_offset) if entry[0] <= address < entry[1]: return True return False elif "DW_AT_low_pc" in DIE.attributes and "DW_AT_high_pc" in DIE.attributes: lo = int(DIE.attributes["DW_AT_low_pc"].value) high_pc = DIE.attributes["DW_AT_high_pc"] highpc_attr_class = describe_form_class(high_pc.form) if highpc_attr_class == 'address': hi = int(high_pc.value) elif highpc_attr_class == 'constant': hi = lo + int(high_pc.value) else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) return lo <= address < hi
def decode_address( dwarf_info, address ): address = int(address, 0) for CU in dwarf_info.iter_CUs(): for DIE in CU.iter_DIEs(): try: if DIE.tag == "DW_TAG_subprogram": low_pc = DIE.attributes["DW_AT_low_pc"].value high_pc_attr = DIE.attributes["DW_AT_high_pc"] high_pc_attr_class = describe_form_class( high_pc_attr.form ) if high_pc_attr_class == "address": high_pc = high_pc_attr.value elif high_pc_attr_class == "constant": high_pc = low_pc + high_pc_attr.value else: print('Error: invalid DW_AT_high_pc class:', high_pc_attr_class) continue if low_pc <= address <= high_pc: return DIE.attributes['DW_AT_name'].value except KeyError: continue return None
def parse_function(range_lists, die): #print(die.attributes) fun = {} try: fun['lowpc'] = die.attributes['DW_AT_low_pc'].value fun['highpc'] = die.attributes['DW_AT_high_pc'].value fun['name'] = die.attributes['DW_AT_name'].value fun['file'] = die.attributes['DW_AT_decl_file'].value fun['line'] = die.attributes['DW_AT_decl_line'].value except KeyError: return None print(describe_form_class(die.attributes['DW_AT_decl_file'].form)) if 'DW_AT_MIPS_linkage_name' in die.attributes: fun['cxx_name'] = die.attributes['DW_AT_MIPS_linkage_name'].value print(fun) # search for parameters and variables fun['params'] = [] fun['vars'] = [] for cc in die.iter_children(): if cc.tag == 'DW_TAG_formal_parameter': param = parse_var(range_lists, cc) if param is not None: fun['params'].append(param) elif cc.tag == 'DW_TAG_variable': var = parse_var(range_lists, cc) if var is not None: fun['vars'].append(var) print('params: {}'.format(fun['params'])) print('vars: {}'.format(fun['vars'])) """ Trying to extract information about the frame size leads to an exception in pyelftools.... if die.attributes['DW_AT_frame_base'].form in ['DW_FORM_data4']: offset = die.attributes['DW_AT_frame_base'].value print('fram_base.offset=0x{:x}'.format(offset)) frame_base = range_lists.get_range_list_at_offset(offset) print(frame_base) """ return fun
def _get_DIE_addrs(self, dwarfinfo, DIE): if "DW_AT_ranges" in DIE.attributes: offset = DIE.attributes["DW_AT_ranges"].value range_lists = dwarfinfo.range_lists() ranges = range_lists.get_range_list_at_offset(offset) # RangeEntry = (begin_offset, end_offset) return ranges elif "DW_AT_low_pc" in DIE.attributes and "DW_AT_high_pc" in DIE.attributes: lo = int(DIE.attributes["DW_AT_low_pc"].value) high_pc = DIE.attributes["DW_AT_high_pc"] highpc_attr_class = describe_form_class(high_pc.form) if highpc_attr_class == 'address': hi = int(high_pc.value) elif highpc_attr_class == 'constant': hi = lo + int(high_pc.value) else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) return [RangeEntry(begin_offset=lo, end_offset=hi)] elif "DW_AT_low_pc" in DIE.attributes: print "only has low_pc...." lo = int(DIE.attributes["DW_AT_low_pc"].value) return [RangeEntry(begin_offset=lo, end_offset=lo)] else: return None
def _addr_in_DIE(self, DIE, address): if "DW_AT_ranges" in DIE.attributes: offset = DIE.attributes["DW_AT_ranges"].value range_lists = self.dwarff.range_lists() ranges = range_lists.get_range_list_at_offset(offset) for entry in ranges: # RangeEntry = (begin_offset, end_offset) if entry[0] <= address < entry[1]: return True return False elif "DW_AT_low_pc" in DIE.attributes and "DW_AT_high_pc" in DIE.attributes: lo = int(DIE.attributes["DW_AT_low_pc"].value) high_pc = DIE.attributes["DW_AT_high_pc"] highpc_attr_class = describe_form_class(high_pc.form) if highpc_attr_class == 'address': hi = int(high_pc.value) elif highpc_attr_class == 'constant': hi = lo + int(high_pc.value) else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) return lo <= address < hi elif "DW_AT_low_pc" in DIE.attributes: lo = int(DIE.attributes["DW_AT_low_pc"].value) return address == lo
def add_function_ranges(elf_filename, range_file, taginfo_args_file, policy_dir, heap_id_start): # Create new defs file for function labels defs_file = open("func_defs.h", "w") defs_file.write("const char * func_defs[] = {\"<none>\",\n") # Check to see if there a subject domains file (maps functions to clusters) # If not, we use one function per cluster subject_domains_file = os.path.join(policy_dir, "subject.defs") has_subject_map = os.path.isfile(subject_domains_file) if has_subject_map: print("Found a subject definition file.") subject_map = load_subject_domains(subject_domains_file) for s in range(1, len(set(subject_map.values())) + 1): # Add this function name to the header file defs if we're making one defs_file.write("\"cluster-" + str(s) + "\",\n") else: print("No subject definition file found, using per-function subjects.") # Get all the malloc() sites, we also put a unique label on each malloc site # in this function. TODO could be separate pass. mallocs = extract_malloc_sites(elf_filename, policy_dir, heap_id_start) # Keep a set of all code locations that we tag. # This is used to clean up some edge cases later and to make sure # that all executable instructions end up with *some* identifier. tagged_instructions = set() # Open ELF with open(elf_filename, 'rb') as elf_file: ef = ELFFile(elf_file) # See if we have DWARF info. Currently required if not ef.has_dwarf_info(): raise Exception(' file has no DWARF info') return dwarfinfo = ef.get_dwarf_info() last_function_number = 0 function_numbers = {} # Code tagging pass 1: # Iterate through each compilation unit, take each function that has # a DW_TAG_subprogram entry, and give proper label. # Some code below taken from decode_funcname() in the ELFtools examples. for CU in dwarfinfo.iter_CUs(): for DIE in CU.iter_DIEs(): try: # We only care about functions (subprograms) if str(DIE.tag) == "DW_TAG_subprogram": if not ("DW_AT_name" in DIE.attributes and "DW_AT_low_pc" in DIE.attributes): print("Skipping a subprogram DIE.") continue func_name = DIE.attributes["DW_AT_name"].value.decode( "utf-8") func_display_name = str(func_name) print("Compartment tagger: tagging function " + func_display_name) # Assign new ID for this function if it's new. # Currently two functions with the same name get the same number, # which is not ideal but a result of how CAPMAP files are saved/loaded. if func_name in function_numbers: function_number = function_numbers[func_name] else: last_function_number += 1 function_number = last_function_number function_numbers[func_name] = function_number # Create new line in defs file for this function if not has_subject_map: defs_file.write("\"" + func_display_name + "\",\n") else: subject_id = subject_map[func_display_name] print("\tGot cluster=" + str(subject_id)) lowpc = DIE.attributes['DW_AT_low_pc'].value # DWARF v4 in section 2.17 describes how to interpret the # DW_AT_high_pc attribute based on the class of its form. # For class 'address' it's taken as an absolute address # (similarly to DW_AT_low_pc); for class 'constant', it's # an offset from DW_AT_low_pc. highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class( highpc_attr.form) if highpc_attr_class == 'address': highpc = highpc_attr.value elif highpc_attr_class == 'constant': highpc = lowpc + highpc_attr.value else: print('Error: invalid DW_AT_high_pc class:', highpc_attr_class) continue # We now have the low addr, high addr, and name. # Add Comp.funcID to taginfo file range_file.write_range(lowpc, highpc, "Comp.funcID") # Add each of these addresses into our set of known instructions for addr in range(lowpc, highpc + 4, 4): tagged_instructions.add(addr) # Set subject ID. Depends on if we having a mapping or are doing default function-subjects if has_subject_map: if not func_display_name in subject_map: raise Exception( "Provided subject domain mapping did not include function " + func_display_name) subject_id = subject_map[func_display_name] else: subject_id = function_number # Then make another pass, add entries for any malloc() call sites within that range for addr in range(lowpc, highpc, 4): if addr in mallocs: alloc_num = mallocs[addr] print("Found a malloc site within this func!") taginfo_args_file.write( '%x %x %s\n' % (addr, addr + 4, str(subject_id) + " 0 " + str(alloc_num))) # Set the field for these instruction words in the taginfo_args file. taginfo_args_file.write( '%x %x %s\n' % (lowpc, highpc, str(subject_id) + " 0 0")) except KeyError: print("KeyError: " + str(KeyError)) continue # Code tagging pass 2: # Some code will not have a DW_TAG_subprogram entry, such as code that came from # a handwritten assembly source file. In this pass we take code that is not yet labeled, # and give it a label based on the compilation unit it came from. for CU in dwarfinfo.iter_CUs(): for DIE in CU.iter_DIEs(): if str(DIE.tag) == "DW_TAG_compile_unit": # Check to see if has both low_pc and high_pc if "DW_AT_low_pc" in DIE.attributes and "DW_AT_high_pc" in DIE.attributes: # Extract low_pc low_pc = DIE.attributes["DW_AT_low_pc"].value # Extract high_pc. Might be encoded as length or addr highpc_attr = DIE.attributes['DW_AT_high_pc'] highpc_attr_class = describe_form_class( highpc_attr.form) if highpc_attr_class == 'address': high_pc = highpc_attr.value elif highpc_attr_class == 'constant': high_pc = low_pc + highpc_attr.value # If any of these words are tagged, skip this pass. # Currently only looking for full CUs that got skipped. for addr in range(low_pc, high_pc, 4): if addr in tagged_instructions: continue # Add function to range, mark ID in arg file range_file.write_range(low_pc, high_pc, "Comp.funcID") function_number += 1 # Create a new function name, def entr cu_src = DIE.attributes["DW_AT_name"].value.decode( "utf-8") function_name = "CU_" + os.path.basename(cu_src) print("Compartment tagger: tagging function " + function_name) # If it's from portASM, add that over it too if "portASM" in function_name: print("Adding context-switch from " + hex(low_pc) + " to " + str(high_pc)) range_file.write_range(low_pc, high_pc, "Comp.context-switch") if not has_subject_map: defs_file.write("\"" + function_name + "\",\n") taginfo_args_file.write( '%x %x %s\n' % (low_pc, high_pc, str(function_number) + " 0 0")) else: if not function_name in subject_map: raise Exception( "Provided subject domain mapping did not include function " + function_name) subject_id = subject_map[function_name] print("\tGot cluster=" + str(subject_id)) print("Writing from %x to %x\n" % (lowpc, highpc)) taginfo_args_file.write( '%x %x %s\n' % (low_pc, high_pc, str(subject_id) + " 0 0")) # Track that these instructions are now labeled for addr in range(low_pc, high_pc + 4, 4): if not addr in tagged_instructions: tagged_instructions.add(addr) continue # Lastly, just print out any executable memory that didn't get a tag. # I've seen some padding bytes at end of .text section flagged by this. for s in ef.iter_sections(): flags = s['sh_flags'] start = s['sh_addr'] end = start + s['sh_size'] added_from_section = False function_name = None if flags & SH_FLAGS.SHF_EXECINSTR: for addr in range(start, end, 4): if not addr in tagged_instructions: print( "Potential warning: found not-tagged executable instr " + hex(addr) + " in section " + s.name) # Finish off definition file, then copy into policy include folder defs_file.write("\"\"\n};\n") defs_file.close() shutil.copy("func_defs.h", os.path.join(policy_dir, "engine", "policy", "include")) print("Done tagging functions.")