summaryrefslogtreecommitdiffstats
path: root/debuginfo-tests/dexter/dex/dextIR
diff options
context:
space:
mode:
Diffstat (limited to 'debuginfo-tests/dexter/dex/dextIR')
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/BuilderIR.py16
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/DebuggerIR.py14
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/DextIR.py129
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/FrameIR.py16
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/LocIR.py45
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/ProgramState.py117
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/StepIR.py103
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/ValueIR.py38
-rw-r--r--debuginfo-tests/dexter/dex/dextIR/__init__.py17
9 files changed, 495 insertions, 0 deletions
diff --git a/debuginfo-tests/dexter/dex/dextIR/BuilderIR.py b/debuginfo-tests/dexter/dex/dextIR/BuilderIR.py
new file mode 100644
index 00000000000..b94a1fb7e81
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/BuilderIR.py
@@ -0,0 +1,16 @@
+# 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
+
+
+class BuilderIR:
+ """Data class which represents the compiler related options passed to Dexter
+ """
+
+ def __init__(self, name: str, cflags: str, ldflags: str):
+ self.name = name
+ self.cflags = cflags
+ self.ldflags = ldflags
diff --git a/debuginfo-tests/dexter/dex/dextIR/DebuggerIR.py b/debuginfo-tests/dexter/dex/dextIR/DebuggerIR.py
new file mode 100644
index 00000000000..5956db602b4
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/DebuggerIR.py
@@ -0,0 +1,14 @@
+# 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
+
+
+class DebuggerIR:
+ """Data class which represents a debugger."""
+
+ def __init__(self, name: str, version: str):
+ self.name = name
+ self.version = version
diff --git a/debuginfo-tests/dexter/dex/dextIR/DextIR.py b/debuginfo-tests/dexter/dex/dextIR/DextIR.py
new file mode 100644
index 00000000000..7638e8b4ab7
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/DextIR.py
@@ -0,0 +1,129 @@
+# 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
+from collections import OrderedDict
+import os
+from typing import List
+
+from dex.dextIR.BuilderIR import BuilderIR
+from dex.dextIR.DebuggerIR import DebuggerIR
+from dex.dextIR.StepIR import StepIR, StepKind
+
+
+def _step_kind_func(context, step):
+ if (step.current_location.path is None or
+ not os.path.exists(step.current_location.path)):
+ return StepKind.FUNC_UNKNOWN
+
+ if any(os.path.samefile(step.current_location.path, f)
+ for f in context.options.source_files):
+ return StepKind.FUNC
+
+ return StepKind.FUNC_EXTERNAL
+
+
+class DextIR:
+ """A full Dexter test report.
+
+ This is composed of all the other *IR classes. They are used together to
+ record Dexter inputs and the resultant debugger steps, providing a single
+ high level access container.
+
+ The Heuristic class works with dexter commands and the generated DextIR to
+ determine the debugging score for a given test.
+
+ Args:
+ commands: { name (str), commands (list[CommandIR])
+ """
+
+ def __init__(self,
+ dexter_version: str,
+ executable_path: str,
+ source_paths: List[str],
+ builder: BuilderIR = None,
+ debugger: DebuggerIR = None,
+ commands: OrderedDict = None):
+ self.dexter_version = dexter_version
+ self.executable_path = executable_path
+ self.source_paths = source_paths
+ self.builder = builder
+ self.debugger = debugger
+ self.commands = commands
+ self.steps: List[StepIR] = []
+
+ def __str__(self):
+ colors = 'rgby'
+ st = '## BEGIN ##\n'
+ color_idx = 0
+ for step in self.steps:
+ if step.step_kind in (StepKind.FUNC, StepKind.FUNC_EXTERNAL,
+ StepKind.FUNC_UNKNOWN):
+ color_idx += 1
+
+ color = colors[color_idx % len(colors)]
+ st += '<{}>{}</>\n'.format(color, step)
+ st += '## END ({} step{}) ##\n'.format(
+ self.num_steps, '' if self.num_steps == 1 else 's')
+ return st
+
+ @property
+ def num_steps(self):
+ return len(self.steps)
+
+ def _get_prev_step_in_this_frame(self, step):
+ """Find the most recent step in the same frame as `step`.
+
+ Returns:
+ StepIR or None if there is no previous step in this frame.
+ """
+ return next((s for s in reversed(self.steps)
+ if s.current_function == step.current_function
+ and s.num_frames == step.num_frames), None)
+
+ def _get_new_step_kind(self, context, step):
+ if step.current_function is None:
+ return StepKind.UNKNOWN
+
+ if len(self.steps) == 0:
+ return _step_kind_func(context, step)
+
+ prev_step = self.steps[-1]
+
+ if prev_step.current_function is None:
+ return StepKind.UNKNOWN
+
+ if prev_step.num_frames < step.num_frames:
+ return _step_kind_func(context, step)
+
+ if prev_step.num_frames > step.num_frames:
+ frame_step = self._get_prev_step_in_this_frame(step)
+ prev_step = frame_step if frame_step is not None else prev_step
+
+ # We're in the same func as prev step, check lineo.
+ if prev_step.current_location.lineno > step.current_location.lineno:
+ return StepKind.VERTICAL_BACKWARD
+
+ if prev_step.current_location.lineno < step.current_location.lineno:
+ return StepKind.VERTICAL_FORWARD
+
+ # We're on the same line as prev step, check column.
+ if prev_step.current_location.column > step.current_location.column:
+ return StepKind.HORIZONTAL_BACKWARD
+
+ if prev_step.current_location.column < step.current_location.column:
+ return StepKind.HORIZONTAL_FORWARD
+
+ # This step is in exactly the same location as the prev step.
+ return StepKind.SAME
+
+ def new_step(self, context, step):
+ assert isinstance(step, StepIR), type(step)
+ step.step_kind = self._get_new_step_kind(context, step)
+ self.steps.append(step)
+ return step
+
+ def clear_steps(self):
+ self.steps.clear()
diff --git a/debuginfo-tests/dexter/dex/dextIR/FrameIR.py b/debuginfo-tests/dexter/dex/dextIR/FrameIR.py
new file mode 100644
index 00000000000..a2c0523b47b
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/FrameIR.py
@@ -0,0 +1,16 @@
+# 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
+from dex.dextIR.LocIR import LocIR
+
+
+class FrameIR:
+ """Data class which represents a frame in the call stack"""
+
+ def __init__(self, function: str, is_inlined: bool, loc: LocIR):
+ self.function = function
+ self.is_inlined = is_inlined
+ self.loc = loc
diff --git a/debuginfo-tests/dexter/dex/dextIR/LocIR.py b/debuginfo-tests/dexter/dex/dextIR/LocIR.py
new file mode 100644
index 00000000000..52a56a8fe80
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/LocIR.py
@@ -0,0 +1,45 @@
+# 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
+import os
+
+
+class LocIR:
+ """Data class which represents a source location."""
+
+ def __init__(self, path: str, lineno: int, column: int):
+ 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 __eq__(self, rhs):
+ return (os.path.exists(self.path) and os.path.exists(rhs.path)
+ and os.path.samefile(self.path, rhs.path)
+ and self.lineno == rhs.lineno
+ and self.column == rhs.column)
+
+ def __lt__(self, rhs):
+ if self.path != rhs.path:
+ return False
+
+ if self.lineno == rhs.lineno:
+ return self.column < rhs.column
+
+ return self.lineno < rhs.lineno
+
+ def __gt__(self, rhs):
+ if self.path != rhs.path:
+ return False
+
+ if self.lineno == rhs.lineno:
+ return self.column > rhs.column
+
+ return self.lineno > rhs.lineno
diff --git a/debuginfo-tests/dexter/dex/dextIR/ProgramState.py b/debuginfo-tests/dexter/dex/dextIR/ProgramState.py
new file mode 100644
index 00000000000..4f05189aed8
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/ProgramState.py
@@ -0,0 +1,117 @@
+# 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 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 (self.path != 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
diff --git a/debuginfo-tests/dexter/dex/dextIR/StepIR.py b/debuginfo-tests/dexter/dex/dextIR/StepIR.py
new file mode 100644
index 00000000000..8111968efe9
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/StepIR.py
@@ -0,0 +1,103 @@
+# 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
+"""Classes which are used to represent debugger steps."""
+
+import json
+
+from collections import OrderedDict
+from typing import List
+from enum import Enum
+from dex.dextIR.FrameIR import FrameIR
+from dex.dextIR.LocIR import LocIR
+from dex.dextIR.ProgramState import ProgramState
+
+
+class StopReason(Enum):
+ BREAKPOINT = 0
+ STEP = 1
+ PROGRAM_EXIT = 2
+ ERROR = 3
+ OTHER = 4
+
+
+class StepKind(Enum):
+ FUNC = 0
+ FUNC_EXTERNAL = 1
+ FUNC_UNKNOWN = 2
+ VERTICAL_FORWARD = 3
+ SAME = 4
+ VERTICAL_BACKWARD = 5
+ UNKNOWN = 6
+ HORIZONTAL_FORWARD = 7
+ HORIZONTAL_BACKWARD = 8
+
+
+class StepIR:
+ """A debugger step.
+
+ Args:
+ watches (OrderedDict): { expression (str), result (ValueIR) }
+ """
+
+ def __init__(self,
+ step_index: int,
+ stop_reason: StopReason,
+ frames: List[FrameIR],
+ step_kind: StepKind = None,
+ watches: OrderedDict = None,
+ program_state: ProgramState = None):
+ self.step_index = step_index
+ self.step_kind = step_kind
+ self.stop_reason = stop_reason
+ self.program_state = program_state
+
+ if frames is None:
+ frames = []
+ self.frames = frames
+
+ if watches is None:
+ watches = {}
+ self.watches = watches
+
+ def __str__(self):
+ try:
+ frame = self.current_frame
+ frame_info = (frame.function, frame.loc.path, frame.loc.lineno,
+ frame.loc.column)
+ except AttributeError:
+ frame_info = (None, None, None, None)
+
+ step_info = (self.step_index, ) + frame_info + (
+ str(self.stop_reason), str(self.step_kind),
+ [w for w in self.watches])
+
+ return '{}{}'.format('. ' * (self.num_frames - 1),
+ json.dumps(step_info))
+
+ @property
+ def num_frames(self):
+ return len(self.frames)
+
+ @property
+ def current_frame(self):
+ if not len(self.frames):
+ return None
+ return self.frames[0]
+
+ @property
+ def current_function(self):
+ try:
+ return self.current_frame.function
+ except AttributeError:
+ return None
+
+ @property
+ def current_location(self):
+ try:
+ return self.current_frame.loc
+ except AttributeError:
+ return LocIR(path=None, lineno=None, column=None)
diff --git a/debuginfo-tests/dexter/dex/dextIR/ValueIR.py b/debuginfo-tests/dexter/dex/dextIR/ValueIR.py
new file mode 100644
index 00000000000..9d532acbb21
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/ValueIR.py
@@ -0,0 +1,38 @@
+# 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
+
+
+class ValueIR:
+ """Data class to store the result of an expression evaluation."""
+
+ def __init__(self,
+ expression: str,
+ value: str,
+ type_name: str,
+ could_evaluate: bool,
+ error_string: str = None,
+ is_optimized_away: bool = False,
+ is_irretrievable: bool = False):
+ self.expression = expression
+ self.value = value
+ self.type_name = type_name
+ self.could_evaluate = could_evaluate
+ self.error_string = error_string
+ self.is_optimized_away = is_optimized_away
+ self.is_irretrievable = is_irretrievable
+
+ def __str__(self):
+ prefix = '"{}": '.format(self.expression)
+ if self.error_string is not None:
+ return prefix + self.error_string
+ if self.value is not None:
+ return prefix + '({}) {}'.format(self.type_name, self.value)
+ return (prefix +
+ 'could_evaluate: {}; irretrievable: {}; optimized_away: {};'
+ .format(self.could_evaluate, self.is_irretrievable,
+ self.is_optimized_away))
+
diff --git a/debuginfo-tests/dexter/dex/dextIR/__init__.py b/debuginfo-tests/dexter/dex/dextIR/__init__.py
new file mode 100644
index 00000000000..463a2c13716
--- /dev/null
+++ b/debuginfo-tests/dexter/dex/dextIR/__init__.py
@@ -0,0 +1,17 @@
+# 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
+"""dextIR: DExTer Intermediate Representation of DExTer's debugger trace output.
+"""
+
+from dex.dextIR.BuilderIR import BuilderIR
+from dex.dextIR.DextIR import DextIR
+from dex.dextIR.DebuggerIR import DebuggerIR
+from dex.dextIR.FrameIR import FrameIR
+from dex.dextIR.LocIR import LocIR
+from dex.dextIR.StepIR import StepIR, StepKind, StopReason
+from dex.dextIR.ValueIR import ValueIR
+from dex.dextIR.ProgramState import ProgramState, SourceLocation, StackFrame
OpenPOWER on IntegriCloud