Пример #1
0
    def display(self, start, lines, logical):

        parcels = ParcelList(self.odb_file.get_structure_list(Parcel))

        # if we are analyzing based on lda, first convert to vma
        if logical:
            start = parcels.lda_to_vma(start)
            if start is None:
                # TODO: Throw exception here?
                return []

        # if we are going backwards
        if lines < 0:
            # Note: Use start+1 to include start in the returned disassembly
            lda_end = parcels.vma_to_lda(start) + 1
            lda_start = lda_end + lines if lda_end > lines else 0
            start = parcels.lda_to_vma(lda_start)
            lines = abs(lines)

        parcels = [p for p in parcels if p.vma_end > start and p.size > 0]

        display = DisplayMaster(self.odb_file, self.analyzer)
        dus = display.display(parcels, start, lines)

        sorted_du = list(dus.values())
        sorted_du.sort(key=lambda x: x.vma, reverse=False)
        return sorted_du
Пример #2
0
 def vma_to_lda(self, vma):
     parcels = ParcelList(self.odb_file.get_structure_list(Parcel))
     return parcels.vma_to_lda(vma)
Пример #3
0
    def test_split_to_data_single_inst_in_parcel(self):
        odb_file = OdbFile(BinaryFile(
            self.get_test_bin_path('code_split_single_instruction/split_parcel_single'), 'elf64-x86-64', 'i386:x86-64'))
        odb_file.execute(LoadOperation())
        odb_file.execute(PassiveScanOperation())

        parcels_before = ParcelList(odb_file.get_structure_list(Parcel))

        # only one instruction in .single
        p = parcels_before.find_parcel_by_vma(0x400598)
        p_text = parcels_before.find_parcel_by_vma(0x400597)
        p_fini = parcels_before.find_parcel_by_vma(0x4005a0)
        p_got = parcels_before.find_parcel_by_vma(0x600fe0)
        num_ldas_before = p.num_ldas
        num_text_ldas_before = p_text.num_ldas
        num_fini_ldas_before = p_fini.num_ldas
        single_lda_before = p.lda_start
        fini_lda_before = p_fini.lda_start
        text_lda_before = p_text.lda_start
        got_lda_before = p_got.lda_start

        # number of parcels before the split
        self.assertEquals(25, len(parcels_before))

        # execute the split operation
        odb_file.execute(SplitParcelOperation(0x400598))

        # number of parcels after the split (should not have changed)
        parcels_after = ParcelList(odb_file.get_structure_list(Parcel))
        self.assertEquals(25, len(parcels_after))

        # get the parcels
        p = parcels_after.find_parcel_by_vma(0x400598)
        p_text = parcels_after.find_parcel_by_vma(0x400597)
        p_fini = parcels_after.find_parcel_by_vma(0x4005a0)

        # make sure they are all unique
        self.assertNotEqual(p, p_text)
        self.assertNotEqual(p, p_fini)
        self.assertNotEqual(p_text, p_fini)

        # check num_ldas in p (1 instruction become 7 data bytes)
        self.assertEquals(7, p.num_ldas)

        # check num_ldas in text didn't change
        self.assertEquals(num_text_ldas_before, p_text.num_ldas)

        # check num_ldas in fini didn't change
        self.assertEquals(num_fini_ldas_before, p_fini.num_ldas)

        # make sure vmas line up
        self.assertEquals(0x4003d0, p_text.vma_start)
        self.assertEquals(0x400598, p_text.vma_end)
        self.assertEquals(0x400598, p.vma_start)
        self.assertEquals(0x40059f, p.vma_end)
        self.assertEquals(0x4005a0, p_fini.vma_start)
        self.assertEquals(0x4005ae, p_fini.vma_end)

        #
        # make sure vma->lda mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(text_lda_before, parcels_after.vma_to_lda(0x4003d0))
        self.assertEquals(text_lda_before+num_text_ldas_before-1, parcels_after.vma_to_lda(0x400597))
        self.assertEquals(single_lda_before, parcels_after.vma_to_lda(0x400598))
        self.assertEquals(True, p_text.is_code)
        self.assertEquals(True, p_fini.is_code)

        # these changed
        self.assertEquals(single_lda_before+1, parcels_after.vma_to_lda(0x400599))
        self.assertEquals(single_lda_before+2, parcels_after.vma_to_lda(0x40059a))
        self.assertEquals(single_lda_before+3, parcels_after.vma_to_lda(0x40059b))
        self.assertEquals(single_lda_before+4, parcels_after.vma_to_lda(0x40059c))
        self.assertEquals(single_lda_before+5, parcels_after.vma_to_lda(0x40059d))
        self.assertEquals(single_lda_before+6, parcels_after.vma_to_lda(0x40059e))
        self.assertEquals(False, p.is_code)

        # 1 instruction turned into 7 data bytes, so it shifted the following parcels by 6 ldas
        self.assertEquals(fini_lda_before+6, parcels_after.vma_to_lda(0x4005a0))
        self.assertEquals(got_lda_before+6, parcels_after.vma_to_lda(0x600fe0))

        #
        # make sure lda->vma mappings line up
        #

        self.assertEquals(text_lda_before, parcels_after.vma_to_lda(0x4003d0))
        self.assertEquals(text_lda_before+num_text_ldas_before-1, parcels_after.vma_to_lda(0x400597))
        self.assertEquals(single_lda_before, parcels_after.vma_to_lda(0x400598))

        # these shouldn't have changed
        self.assertEquals(0x4003d0, parcels_after.lda_to_vma(text_lda_before))
        self.assertEquals(0x400597, parcels_after.lda_to_vma(text_lda_before+num_text_ldas_before-1))
        self.assertEquals(0x400598, parcels_after.lda_to_vma(single_lda_before))

        # these changed
        self.assertEquals(0x400599, parcels_after.lda_to_vma(single_lda_before+1))
        self.assertEquals(0x40059a, parcels_after.lda_to_vma(single_lda_before+2))
        self.assertEquals(0x40059b, parcels_after.lda_to_vma(single_lda_before+3))
        self.assertEquals(0x40059c, parcels_after.lda_to_vma(single_lda_before+4))
        self.assertEquals(0x40059d, parcels_after.lda_to_vma(single_lda_before+5))
        self.assertEquals(0x40059e, parcels_after.lda_to_vma(single_lda_before+6))

        # 1 instruction turned into 7 data bytes, so it shifted the following parcels by 6 ldas
        self.assertEquals(0x4005a0, parcels_after.lda_to_vma(fini_lda_before+6))
        self.assertEquals(0x600fe0, parcels_after.lda_to_vma(got_lda_before+6))
Пример #4
0
    def test_split_to_data_at_end_of_parcel(self):
        odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64'))
        odb_file.execute(LoadOperation())
        odb_file.execute(PassiveScanOperation())

        parcels_before = ParcelList(odb_file.get_structure_list(Parcel))

        # last instruction in .plt
        p = parcels_before.find_parcel_by_vma(0x4029bb)
        p3 = parcels_before.find_parcel_by_vma(0x4029c0)
        num_p1_ldas_before = p.num_ldas
        num_p3_ldas_before = p3.num_ldas
        plt_lda_before = parcels_before.vma_to_lda(0x402320)
        text_lda_before = parcels_before.vma_to_lda(0x4029c0)

        # number of parcels before the split
        self.assertEquals(25, len(parcels_before))

        # execute the split operation
        odb_file.execute(SplitParcelOperation(0x4029bb))

        # number of parcels after the split (should only add one more)
        parcels_after = ParcelList(odb_file.get_structure_list(Parcel))
        self.assertEquals(26, len(parcels_after))

        # get the two parcels (plus the .text one following)
        p1 = parcels_after.find_parcel_by_vma(0x402320)
        p2 = parcels_after.find_parcel_by_vma(0x4029bb)
        p3 = parcels_after.find_parcel_by_vma(0x4029c0)

        # make sure they are all unique
        self.assertNotEqual(p1, p2)
        self.assertNotEqual(p1, p3)
        self.assertNotEqual(p2, p3)

        # check num_ldas in p1 (5 instructions)
        self.assertEquals(num_p1_ldas_before - 1, p1.num_ldas)

        # check num_ldas in p2 (this one instruction has now become 5 data bytes)
        self.assertEquals(5, p2.num_ldas)

        # check num_ldas in p3 (should not have changed)
        self.assertEquals(num_p3_ldas_before, p3.num_ldas)

        # make sure vmas line up
        self.assertEquals(0x402320, p1.vma_start)
        self.assertEquals(0x4029bb, p1.vma_end)
        self.assertEquals(0x4029bb, p2.vma_start)
        self.assertEquals(0x4029c0, p2.vma_end)
        self.assertEquals(0x4029c0, p3.vma_start)
        self.assertEquals(0x412bec, p3.vma_end)

        #
        # make sure vma->lda mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(plt_lda_before, parcels_after.vma_to_lda(0x402320))
        self.assertEquals(plt_lda_before+num_p1_ldas_before-2, parcels_after.vma_to_lda(0x4029b6))
        self.assertEquals(plt_lda_before+num_p1_ldas_before-1, parcels_after.vma_to_lda(0x4029bb))
        self.assertEquals(True, p1.is_code)
        self.assertEquals(True, p3.is_code)

        # these changed
        self.assertEquals(plt_lda_before+num_p1_ldas_before, parcels_after.vma_to_lda(0x4029bc))
        self.assertEquals(plt_lda_before+num_p1_ldas_before+1, parcels_after.vma_to_lda(0x4029bd))
        self.assertEquals(plt_lda_before+num_p1_ldas_before+2, parcels_after.vma_to_lda(0x4029be))
        self.assertEquals(plt_lda_before+num_p1_ldas_before+3, parcels_after.vma_to_lda(0x4029bf))
        self.assertEquals(plt_lda_before+num_p1_ldas_before+4, parcels_after.vma_to_lda(0x4029c0))
        self.assertEquals(False, p2.is_code)

        # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas
        self.assertEquals(text_lda_before+4, parcels_after.vma_to_lda(0x4029c0))

        #
        # make sure lda->vma mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(0x402320, parcels_after.lda_to_vma(plt_lda_before))
        self.assertEquals(0x4029b6, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before-2))
        self.assertEquals(0x4029bb, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before-1))

        # these changed
        self.assertEquals(0x4029bc, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before))
        self.assertEquals(0x4029bd, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+1))
        self.assertEquals(0x4029be, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+2))
        self.assertEquals(0x4029bf, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+3))
        self.assertEquals(0x4029c0, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+4))

        # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas
        self.assertEquals(0x4029c0, parcels_after.lda_to_vma(text_lda_before+4))
Пример #5
0
    def test_split_to_data_basic(self):
        odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64'))
        odb_file.execute(LoadOperation())
        odb_file.execute(PassiveScanOperation())

        parcels_before = ParcelList(odb_file.get_structure_list(Parcel))
        p = parcels_before.find_parcel_by_vma(0x4029c0)
        num_p1_ldas_before = p.num_ldas
        text_lda_before = parcels_before.vma_to_lda(0x4029c0)
        fini_lda_before = parcels_before.vma_to_lda(0x412bec)

        # number of parcels before the split
        self.assertEquals(25, len(parcels_before))

        # execute the split operation
        odb_file.execute(SplitParcelOperation(0x4029d5))

        # number of parcels after the split
        parcels_after = ParcelList(odb_file.get_structure_list(Parcel))
        self.assertEquals(27, len(parcels_after))

        # get the three parcels
        p1 = parcels_after.find_parcel_by_vma(0x4029c0)
        p2 = parcels_after.find_parcel_by_vma(0x4029d5)
        p3 = parcels_after.find_parcel_by_vma(0x4029da)

        # make sure they are all unique
        self.assertNotEqual(p1, p2)
        self.assertNotEqual(p1, p3)
        self.assertNotEqual(p2, p3)

        # check num_ldas in p1 (5 instructions)
        self.assertEquals(5, p1.num_ldas)

        # check num_ldas in p2 (this one instruction has now become 5 data bytes)
        self.assertEquals(5, p2.num_ldas)

        # check num_ldas in p3 (less 5 from p1 and less 1 from p2 - remember it used to only be 1 lda before the split)
        self.assertEquals(num_p1_ldas_before - 5 - 1, p3.num_ldas)

        # make sure vmas line up
        self.assertEquals(0x4029c0, p1.vma_start)
        self.assertEquals(0x4029d5, p1.vma_end)
        self.assertEquals(0x4029d5, p2.vma_start)
        self.assertEquals(0x4029da, p2.vma_end)
        self.assertEquals(0x4029da, p3.vma_start)
        self.assertEquals(0x412bec, p3.vma_end)

        #
        # make sure vma->lda mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(text_lda_before, parcels_after.vma_to_lda(0x4029c0))
        self.assertEquals(text_lda_before+5, parcels_after.vma_to_lda(0x4029d5))
        self.assertEquals(True, p1.is_code)
        self.assertEquals(True, p3.is_code)

        # these changed
        self.assertEquals(text_lda_before+6, parcels_after.vma_to_lda(0x4029d6))
        self.assertEquals(text_lda_before+7, parcels_after.vma_to_lda(0x4029d7))
        self.assertEquals(text_lda_before+8, parcels_after.vma_to_lda(0x4029d8))
        self.assertEquals(text_lda_before+9, parcels_after.vma_to_lda(0x4029d9))
        self.assertEquals(text_lda_before+10, parcels_after.vma_to_lda(0x4029da))
        self.assertEquals(text_lda_before+11, parcels_after.vma_to_lda(0x4029db))
        self.assertEquals(False, p2.is_code)

        # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas
        self.assertEquals(fini_lda_before+4, parcels_after.vma_to_lda(0x412bec))

        #
        # make sure lda->vma mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(0x4029c0, parcels_after.lda_to_vma(text_lda_before))
        self.assertEquals(0x4029d5, parcels_after.lda_to_vma(text_lda_before+5))

        # these changed
        self.assertEquals(0x4029d6, parcels_after.lda_to_vma(text_lda_before+6))
        self.assertEquals(0x4029d7, parcels_after.lda_to_vma(text_lda_before+7))
        self.assertEquals(0x4029d8, parcels_after.lda_to_vma(text_lda_before+8))
        self.assertEquals(0x4029d9, parcels_after.lda_to_vma(text_lda_before+9))
        self.assertEquals(0x4029da, parcels_after.lda_to_vma(text_lda_before+10))
        self.assertEquals(0x4029db, parcels_after.lda_to_vma(text_lda_before+11))

        # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas
        self.assertEquals(0x412bec, parcels_after.lda_to_vma(fini_lda_before+4))
Пример #6
0
    def test_split_to_data_at_start_of_parcel(self):
        odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64'))
        odb_file.execute(LoadOperation())
        odb_file.execute(PassiveScanOperation())

        parcels_before = ParcelList(odb_file.get_structure_list(Parcel))

        # start of .fini section
        p = parcels_before.find_parcel_by_vma(0x412bec)
        num_p1_ldas_before = p.num_ldas
        fini_lda_before = parcels_before.vma_to_lda(0x412bec)

        # number of parcels before the split
        self.assertEquals(25, len(parcels_before))

        # execute the split operation
        odb_file.execute(SplitParcelOperation(0x412bec))

        # number of parcels after the split (should only add one more)
        parcels_after = ParcelList(odb_file.get_structure_list(Parcel))
        self.assertEquals(26, len(parcels_after))

        # get the two parcels
        p1 = parcels_after.find_parcel_by_vma(0x412bec)
        p2 = parcels_after.find_parcel_by_vma(0x412bf0)

        # make sure they are unique
        self.assertNotEqual(p1, p2)

        # check num_ldas in p1 (4 data bytes)
        self.assertEquals(4, p1.num_ldas)

        # check num_ldas in p2
        self.assertEquals(2, p2.num_ldas)

        # make sure vmas line up
        self.assertEquals(0x412bec, p1.vma_start)
        self.assertEquals(0x412bf0, p1.vma_end)
        self.assertEquals(0x412bf0, p2.vma_start)
        self.assertEquals(0x412bf5, p2.vma_end)

        #
        # make sure vma->lda mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(fini_lda_before, parcels_after.vma_to_lda(0x412bec))
        self.assertEquals(True, p2.is_code)

        # these changed
        self.assertEquals(fini_lda_before+1, parcels_after.vma_to_lda(0x412bed))
        self.assertEquals(fini_lda_before+2, parcels_after.vma_to_lda(0x412bee))
        self.assertEquals(fini_lda_before+3, parcels_after.vma_to_lda(0x412bef))
        self.assertEquals(fini_lda_before+4, parcels_after.vma_to_lda(0x412bf0))
        self.assertEquals(fini_lda_before+5, parcels_after.vma_to_lda(0x412bf4))
        self.assertEquals(False, p1.is_code)

        #
        # make sure lda->vma mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(0x412bec, parcels_after.lda_to_vma(fini_lda_before))

        # these changed
        self.assertEquals(0x412bed, parcels_after.lda_to_vma(fini_lda_before+1))
        self.assertEquals(0x412bee, parcels_after.lda_to_vma(fini_lda_before+2))
        self.assertEquals(0x412bef, parcels_after.lda_to_vma(fini_lda_before+3))
        self.assertEquals(0x412bf0, parcels_after.lda_to_vma(fini_lda_before+4))
        self.assertEquals(0x412bf4, parcels_after.lda_to_vma(fini_lda_before+5))
Пример #7
0
class BranchGraphView(list):
    def __init__(self, odb_file, vma):
        self.odb_file = odb_file
        start = None
        end = None
        self.parcels = ParcelList(odb_file.get_structure_list(Parcel))

        # first, some validation
        p = self.parcels.find_parcel_by_vma(vma)
        if p:
            # initialize to parcel boundaries
            start = p.vma_start
            end = p.vma_end

            # if this is not in a code section
            if not p.is_code:
                raise Exception(
                    "Graph view is not available for data sections!")

        # else, invalid address
        else:
            raise Exception(
                "Graph view is not available for invalid address 0x%x!" % vma)

        if type(odb_file.binary) == BinaryString:
            # TODO: Handle nonzero base address
            start = 0
            end = odb_file.binary.size

        functions = sorted(odb_file.get_structure_list(Function),
                           key=lambda f: f.vma)
        for f in functions:
            if vma >= f.vma:
                start = f.vma
            elif vma < f.vma:
                end = f.vma
                break

        # get all the branches within this function
        # TODO: Deal with indirect branches (i.e., jmp rax)
        branches = filter(
            lambda b: b.srcAddr >= start and b.srcAddr < end and b.
            targetAddr >= start and b.targetAddr < end,
            odb_file.get_structure_list(Branch))

        # dict of nodes, keyed by starting address of the block
        self._nodes = {}
        thisBlock = start

        for b in sorted(branches, key=lambda b: b.srcAddr):
            # address if the branch is not taken (i.e., the addr of the next instruction)
            no = b.srcAddr + b.instrLen

            # address if the branch is taken
            yes = b.targetAddr

            # first node
            self._nodes[thisBlock] = BranchGraphNode(thisBlock, b.srcAddr,
                                                     no - thisBlock, yes, no)

            # advance to next block
            thisBlock = no

        # make last block
        if thisBlock != end:
            end_line = self.parcels.vma_to_lda(end - 1)
            last_addr = self.parcels.lda_to_vma(end_line)
            self._nodes[thisBlock] = BranchGraphNode(thisBlock, last_addr,
                                                     end - thisBlock, None,
                                                     None)

        # for each target 'yes' branch address
        # NOTE: The 'no' branch addresses are guaranteed to be nodes by this point
        # NOTE: We can't iterate over the nodes with iteritems() since we modify the dictionary in the loop
        for addr in [n.yesAddr for n in self._nodes.values()]:
            # if this is a new node
            if addr not in self._nodes:
                # find the node that contains this address (the parent) and split it
                for parent in list(self._nodes.values()):
                    if addr in parent:
                        newNode = parent.split(addr, self.parcels)
                        self._nodes[addr] = newNode

    '''
    {
        nodes:
        [
            {id:X, instructions: [du1, du2, du3, du4 ... }
            {id:Y, instructions: [du9, du10, du11 .... }
            ....
        ]
        links: [
            { from:x, to:y, type: 'taken' }
            { from:y, to: z, type: 'notTaken'}
            { from:o, to: q, type: 'unconditional'}
        ]
    }
    '''

    def getNodes(self):

        dasm = Disassembler(self.odb_file)

        # convert _nodes to representation needed by front end
        nodes = []
        for startAddr, node in self._nodes.items():
            startLine = self.parcels.vma_to_lda(startAddr)
            endLine = self.parcels.vma_to_lda(startAddr + node.size)
            if endLine is None:
                endLine = self.parcels.sum_ldas()
            dus = dasm.display(startAddr, endLine - startLine, False)
            nodes.append({'id': node.id, 'instructions': dus})

        return nodes

    def getLinks(self):
        links = []
        # convert _nodes to representation needed by front end
        for startAddr, node in self._nodes.items():
            try:
                if node.noAddr:
                    links.append({
                        'from': node.id,
                        'to': self._nodes[node.noAddr].id,
                        'type': 'notTaken'
                    })
                    links.append({
                        'from': node.id,
                        'to': self._nodes[node.yesAddr].id,
                        'type': 'taken'
                    })
                elif node.yesAddr:
                    links.append({
                        'from': node.id,
                        'to': self._nodes[node.yesAddr].id,
                        'type': 'unconditional'
                    })
                else:
                    # else, this is the last node in the function, which has no links
                    pass
            except Exception as e:
                # for now, keep going if something goes wrong
                # AVD@9/8/15: An exception can happen right now if the last instruction in the function is a
                #             branch to somewhere in the middle of the function.  The problem is that the "no"
                #             address is not within the function, since it is actually the first instruction of
                #             the next function.  Need to revisit this and see if we can do better than just
                #             skipping this link.
                continue

        return links

    nodes = property(getNodes)
    links = property(getLinks)
Пример #8
0
    def test_basic_active_scan(self):

        # we load this ELF as a raw binary, because it has an invalid opcode fairly early on
        odb_file = OdbFile(
            BinaryFile(self.get_test_bin_path('mkdir'), 'elf64-x86-64',
                       'i386:x86-64'))
        odb_file.execute(LoadOperation())
        odb_file.execute(PassiveScanOperation())

        parcels_before = ParcelList(odb_file.get_structure_list(Parcel))
        p = parcels_before.find_parcel_by_vma(0x4002ce)
        gnu_hash_lda_before = parcels_before.vma_to_lda(0x4002cd)
        dynsym_lda_before = parcels_before.vma_to_lda(0x4002e0)
        dynstr_lda_before = parcels_before.vma_to_lda(0x400a18)

        # number of parcels before the split
        self.assertEquals(24, len(parcels_before))

        # execute the split operation
        odb_file.execute(ActiveScanOperation(0x4002ce))

        # number of parcels after the split
        parcels_after = ParcelList(odb_file.get_structure_list(Parcel))
        self.assertEquals(26, len(parcels_after))

        # get the three parcels
        p1 = parcels_after.find_parcel_by_vma(0x400298)
        p2 = parcels_after.find_parcel_by_vma(0x4002ce)
        p3 = parcels_after.find_parcel_by_vma(0x4002d5)

        # make sure they are all unique
        self.assertNotEqual(p1, p2)
        self.assertNotEqual(p1, p3)
        self.assertNotEqual(p2, p3)

        # check num_ldas in p1 (54 bytes)
        self.assertEquals(54, p1.num_ldas)

        # check num_ldas in p2 (3 instructions)
        self.assertEquals(3, p2.num_ldas)

        # check num_ldas in p3 (7 bytes)
        self.assertEquals(7, p3.num_ldas)

        # make sure vmas line up
        self.assertEquals(0x400298, p1.vma_start)
        self.assertEquals(0x4002ce, p1.vma_end)
        self.assertEquals(0x4002ce, p2.vma_start)
        self.assertEquals(0x4002d5, p2.vma_end)
        self.assertEquals(0x4002d5, p3.vma_start)
        self.assertEquals(0x4002dc, p3.vma_end)

        #
        # make sure vma->lda mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(gnu_hash_lda_before,
                          parcels_after.vma_to_lda(0x4002cd))
        self.assertEquals(gnu_hash_lda_before + 1,
                          parcels_after.vma_to_lda(0x4002ce))
        self.assertEquals(False, p1.is_code)
        self.assertEquals(False, p3.is_code)

        # these changed
        self.assertEquals(gnu_hash_lda_before + 2,
                          parcels_after.vma_to_lda(0x4002d0))
        self.assertEquals(gnu_hash_lda_before + 3,
                          parcels_after.vma_to_lda(0x4002d2))

        self.assertEquals(gnu_hash_lda_before + 4,
                          parcels_after.vma_to_lda(0x4002d5))
        self.assertEquals(gnu_hash_lda_before + 5,
                          parcels_after.vma_to_lda(0x4002d6))
        self.assertEquals(gnu_hash_lda_before + 6,
                          parcels_after.vma_to_lda(0x4002d7))
        self.assertEquals(gnu_hash_lda_before + 7,
                          parcels_after.vma_to_lda(0x4002d8))
        self.assertEquals(gnu_hash_lda_before + 8,
                          parcels_after.vma_to_lda(0x4002d9))
        self.assertEquals(gnu_hash_lda_before + 9,
                          parcels_after.vma_to_lda(0x4002da))
        self.assertEquals(gnu_hash_lda_before + 10,
                          parcels_after.vma_to_lda(0x4002db))
        self.assertEquals(True, p2.is_code)

        # 7 bytes turned into 3 instructions, so it shifted the following parcels by -4 ldas
        self.assertEquals(dynsym_lda_before - 4,
                          parcels_after.vma_to_lda(0x4002e0))
        self.assertEquals(dynstr_lda_before - 4,
                          parcels_after.vma_to_lda(0x400a18))

        #
        # make sure lda->vma mappings line up
        #

        # these shouldn't have changed
        self.assertEquals(0x4002cd,
                          parcels_after.lda_to_vma(gnu_hash_lda_before))
        self.assertEquals(0x4002ce,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 1))

        # these changed
        self.assertEquals(0x4002d0,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 2))
        self.assertEquals(0x4002d2,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 3))

        self.assertEquals(0x4002d5,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 4))
        self.assertEquals(0x4002d6,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 5))
        self.assertEquals(0x4002d7,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 6))
        self.assertEquals(0x4002d8,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 7))
        self.assertEquals(0x4002d9,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 8))
        self.assertEquals(0x4002da,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 9))
        self.assertEquals(0x4002db,
                          parcels_after.lda_to_vma(gnu_hash_lda_before + 10))

        # 7 bytes turned into 3 instructions, so it shifted the following parcels by -4 ldas
        self.assertEquals(0x4002e0,
                          parcels_after.lda_to_vma(dynsym_lda_before - 4))
        self.assertEquals(0x400a18,
                          parcels_after.lda_to_vma(dynstr_lda_before - 4))