summaryrefslogtreecommitdiff
path: root/cross-project-tests/debuginfo-tests/dexter/dex/dextIR/ProgramState.py
blob: a1de5fbcf363de4d66f7dd3d2ff669c6b257d270 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# DExTer : Debugging Experience Tester
# ~~~~~~   ~         ~~         ~   ~~
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Set of data classes for representing the complete debug program state at a
fixed point in execution.
"""

import os

from collections import OrderedDict
from pathlib import PurePath
from typing import List

class SourceLocation:
    def __init__(self, path: str = None, lineno: int = None, column: int = None):
        if path:
            path = os.path.normcase(path)
        self.path = path
        self.lineno = lineno
        self.column = column

    def __str__(self):
        return '{}({}:{})'.format(self.path, self.lineno, self.column)

    def match(self, other) -> bool:
        """Returns true iff all the properties that appear in `self` have the
        same value in `other`, but not necessarily vice versa.
        """
        if not other or not isinstance(other, SourceLocation):
            return False

        if self.path and (other.path is None or (PurePath(self.path) != PurePath(other.path))):
            return False

        if self.lineno and (self.lineno != other.lineno):
            return False

        if self.column and (self.column != other.column):
            return False

        return True


class StackFrame:
    def __init__(self,
                 function: str = None,
                 is_inlined: bool = None,
                 location: SourceLocation = None,
                 watches: OrderedDict = None):
        if watches is None:
            watches = {}

        self.function = function
        self.is_inlined = is_inlined
        self.location = location
        self.watches = watches

    def __str__(self):
        return '{}{}: {} | {}'.format(
            self.function,
            ' (inlined)' if self.is_inlined else '',
            self.location,
            {k: str(self.watches[k]) for k in self.watches})

    def match(self, other) -> bool:
        """Returns true iff all the properties that appear in `self` have the
        same value in `other`, but not necessarily vice versa.
        """
        if not other or not isinstance(other, StackFrame):
            return False

        if self.location and not self.location.match(other.location):
            return False

        if self.watches:
            for name in iter(self.watches):
                try:
                    if isinstance(self.watches[name], dict):
                        for attr in iter(self.watches[name]):
                            if (getattr(other.watches[name], attr, None) !=
                                    self.watches[name][attr]):
                                return False
                    else:
                        if other.watches[name].value != self.watches[name]:
                            return False
                except KeyError:
                    return False

        return True

class ProgramState:
    def __init__(self, frames: List[StackFrame] = None):
        self.frames = frames

    def __str__(self):
        return '\n'.join(map(
            lambda enum: 'Frame {}: {}'.format(enum[0], enum[1]),
            enumerate(self.frames)))

    def match(self, other) -> bool:
        """Returns true iff all the properties that appear in `self` have the
        same value in `other`, but not necessarily vice versa.
        """
        if not other or not isinstance(other, ProgramState):
            return False

        if self.frames:
            for idx, frame in enumerate(self.frames):
                try:
                    if not frame.match(other.frames[idx]):
                        return False
                except (IndexError, KeyError):
                    return False

        return True