• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2024 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import logging
19import subprocess  # noqa: S404
20from dataclasses import dataclass
21from pathlib import Path
22
23from pytest import fixture
24
25from arkdb.runnable_module import ScriptFile
26
27LOG = logging.getLogger(__name__)
28
29
30@dataclass
31class Options:
32    app_path: Path = Path("bin", "ark_disasm")
33    verbose: bool = False
34
35
36class DisassemblerError(Exception):
37    pass
38
39
40class Disassembler:
41    def __init__(self, options: Options) -> None:
42        self.options = options
43
44    def run(
45        self,
46        panda_file: Path,
47        output_file: Path,
48        cwd: Path = Path(),
49    ):
50        args = [str(self.options.app_path)]
51        if self.options.verbose:
52            args.append(f"--verbose={self.options.verbose}")
53        args += [str(panda_file), str(output_file)]
54        LOG.info("Disassemble %s", args)
55        proc = subprocess.run(  # noqa: S603
56            args=args,
57            cwd=cwd,
58            text=True,
59            capture_output=True,
60        )
61        if proc.returncode == 1:
62            raise DisassemblerError(f"Stdout:\n{proc.stdout}\nStderr:\n{proc.stderr}")
63        proc.check_returncode()
64        return proc.stdout
65
66
67@fixture
68def ark_disassembler(
69    ark_disassembler_options: Options,
70) -> Disassembler:
71    return Disassembler(ark_disassembler_options)
72
73
74class ScriptFileDisassembler:
75    def __init__(self, tmp_path: Path, ark_disassembler: Disassembler):
76        self._tmp_path = tmp_path
77        self._ark_disassembler = ark_disassembler
78
79    def disassemble(self, file: ScriptFile) -> ScriptFile:
80        file.check_exists()
81        pa_file = file.panda_file.parent / f"{file.panda_file.stem}.pa"
82        self._ark_disassembler.run(file.panda_file, pa_file, cwd=self._tmp_path)
83        file.disasm_file = pa_file
84        return file
85
86
87@fixture
88def script_disassembler(
89    tmp_path: Path,
90    ark_disassembler: Disassembler,
91) -> ScriptFileDisassembler:
92    """
93    Return :class:`StringCodeCompiler` instance that can compile ``ets``-file.
94    """
95    return ScriptFileDisassembler(tmp_path, ark_disassembler)
96