Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
        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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
Archivo: pyelf.py Proyecto: Sauci/pyelf
    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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
    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))
Ejemplo n.º 11
0
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
Ejemplo n.º 12
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
Ejemplo n.º 13
0
 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
Ejemplo n.º 15
0
Archivo: dwarf.py Proyecto: ekiwi/ucta
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
Ejemplo n.º 16
0
 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
Ejemplo n.º 17
0
 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
Ejemplo n.º 18
0
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.")