From d2f2d9366ea389e9ac593e0ee214e5f31a04414f Mon Sep 17 00:00:00 2001 From: hugsy Date: Tue, 30 Jul 2024 10:06:39 -0700 Subject: [PATCH 1/3] moved cemu to using rye --- .gitignore | 6 +- .pre-commit-config.yaml | 12 +- .pylintrc | 886 ------------------ .python-version | 1 + README.md | 4 +- cemu/shortcuts.py | 55 -- pyproject.toml | 82 +- requirements-dev.lock | 58 ++ requirements.lock | 40 + {cemu => src/cemu}/__init__.py | 0 {cemu => src/cemu}/__main__.py | 31 +- {cemu => src/cemu}/arch/__init__.py | 10 +- {cemu => src/cemu}/arch/arm.py | 1 - {cemu => src/cemu}/arch/generic.py | 0 {cemu => src/cemu}/arch/mips.py | 24 +- {cemu => src/cemu}/arch/ppc.py | 0 {cemu => src/cemu}/arch/sparc.py | 24 +- {cemu => src/cemu}/arch/x86.py | 8 +- {cemu => src/cemu}/cli/__init__.py | 0 {cemu => src/cemu}/cli/repl.py | 30 +- {cemu => src/cemu}/const.py | 0 {cemu => src/cemu}/core.py | 18 +- {cemu => src/cemu}/emulator.py | 47 +- {cemu => src/cemu}/errors.py | 0 .../cemu}/examples/aarch64_execve_bin_sh.asm | 0 {cemu => src/cemu}/examples/arm_nops.raw | 0 .../cemu}/examples/arm_sys_exec_bin_sh.asm | 0 .../cemu}/examples/mips_sys_exec_bin_sh.asm | 0 .../cemu}/examples/mipsbe_sys_exec_bin_sh.asm | 0 .../examples/sparc64_sys_exec_bin_sh.asm | 0 {cemu => src/cemu}/examples/sparc_nops.raw | Bin .../cemu}/examples/sparc_sys_exec_bin_sh.asm | 0 .../examples/x86_32_read_flag_null_free.asm | 0 .../cemu}/examples/x86_32_sys_exec_bin_sh.asm | 0 .../x86_32_sys_exec_bin_sh_null_free.asm | 0 .../examples/x86_64_read_flag_null_free.asm | 0 .../cemu}/examples/x86_64_sys_exec_bin_sh.asm | 0 .../x86_64_sys_exec_bin_sh_null_free.asm | 0 {cemu => src/cemu}/examples/x86_nops.raw | 0 {cemu => src/cemu}/exceptions.py | 0 {cemu => src/cemu}/exports.py | 8 +- .../cemu/img}/cemu-windows-dark.png | Bin .../cemu/img}/cemu-windows-light.png | Bin {cemu => src/cemu}/img/icon.png | Bin {cemu => src/cemu}/img/new_logo.png | Bin {cemu => src/cemu}/log.py | 0 {cemu => src/cemu}/memory.py | 18 +- {cemu => src/cemu}/os.py | 0 {cemu => src/cemu}/plugins/__init__.py | 0 .../cemu}/plugins/pyconsole/__init__.py | 0 .../cemu}/plugins/pyconsole/console.py | 17 +- {cemu => src/cemu}/plugins/scratchboard.py | 0 {cemu => src/cemu}/settings.py | 0 src/cemu/shortcuts.py | 54 ++ {cemu => src/cemu}/styles/default.qss | 0 {cemu => src/cemu}/syscalls/linux/aarch64.csv | 0 .../cemu}/syscalls/linux/arm-thumb.csv | 0 {cemu => src/cemu}/syscalls/linux/arm.csv | 0 {cemu => src/cemu}/syscalls/linux/mips.csv | 0 {cemu => src/cemu}/syscalls/linux/mips64.csv | 0 {cemu => src/cemu}/syscalls/linux/sparc.csv | 0 {cemu => src/cemu}/syscalls/linux/x86-64.csv | 0 {cemu => src/cemu}/syscalls/linux/x86.csv | 0 {cemu => src/cemu}/templates/about.html | 0 {cemu => src/cemu}/templates/cemu.ini | 0 .../cemu}/templates/linux/template.asm | 0 {cemu => src/cemu}/templates/linux/template.c | 0 {cemu => src/cemu}/ui/__init__.py | 0 {cemu => src/cemu}/ui/codeeditor.py | 16 +- {cemu => src/cemu}/ui/command.py | 16 +- {cemu => src/cemu}/ui/highlighter.py | 0 {cemu => src/cemu}/ui/log.py | 0 {cemu => src/cemu}/ui/main.py | 73 +- {cemu => src/cemu}/ui/mapping.py | 35 +- {cemu => src/cemu}/ui/memory.py | 8 +- {cemu => src/cemu}/ui/registers.py | 14 +- {cemu => src/cemu}/ui/utils.py | 8 +- {cemu => src/cemu}/utils.py | 8 +- tests/test_basic.py | 9 +- tests/test_memory.py | 28 +- 80 files changed, 334 insertions(+), 1315 deletions(-) delete mode 100644 .pylintrc create mode 100644 .python-version delete mode 100644 cemu/shortcuts.py create mode 100644 requirements-dev.lock create mode 100644 requirements.lock rename {cemu => src/cemu}/__init__.py (100%) rename {cemu => src/cemu}/__main__.py (51%) rename {cemu => src/cemu}/arch/__init__.py (95%) rename {cemu => src/cemu}/arch/arm.py (99%) rename {cemu => src/cemu}/arch/generic.py (100%) rename {cemu => src/cemu}/arch/mips.py (69%) rename {cemu => src/cemu}/arch/ppc.py (100%) rename {cemu => src/cemu}/arch/sparc.py (68%) rename {cemu => src/cemu}/arch/x86.py (94%) rename {cemu => src/cemu}/cli/__init__.py (100%) rename {cemu => src/cemu}/cli/repl.py (90%) rename {cemu => src/cemu}/const.py (100%) rename {cemu => src/cemu}/core.py (87%) rename {cemu => src/cemu}/emulator.py (92%) rename {cemu => src/cemu}/errors.py (100%) rename {cemu => src/cemu}/examples/aarch64_execve_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/arm_nops.raw (100%) rename {cemu => src/cemu}/examples/arm_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/mips_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/mipsbe_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/sparc64_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/sparc_nops.raw (100%) rename {cemu => src/cemu}/examples/sparc_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/x86_32_read_flag_null_free.asm (100%) rename {cemu => src/cemu}/examples/x86_32_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/x86_32_sys_exec_bin_sh_null_free.asm (100%) rename {cemu => src/cemu}/examples/x86_64_read_flag_null_free.asm (100%) rename {cemu => src/cemu}/examples/x86_64_sys_exec_bin_sh.asm (100%) rename {cemu => src/cemu}/examples/x86_64_sys_exec_bin_sh_null_free.asm (100%) rename {cemu => src/cemu}/examples/x86_nops.raw (100%) rename {cemu => src/cemu}/exceptions.py (100%) rename {cemu => src/cemu}/exports.py (94%) rename {images/screenshots => src/cemu/img}/cemu-windows-dark.png (100%) rename {images/screenshots => src/cemu/img}/cemu-windows-light.png (100%) rename {cemu => src/cemu}/img/icon.png (100%) rename {cemu => src/cemu}/img/new_logo.png (100%) rename {cemu => src/cemu}/log.py (100%) rename {cemu => src/cemu}/memory.py (92%) rename {cemu => src/cemu}/os.py (100%) rename {cemu => src/cemu}/plugins/__init__.py (100%) rename {cemu => src/cemu}/plugins/pyconsole/__init__.py (100%) rename {cemu => src/cemu}/plugins/pyconsole/console.py (92%) rename {cemu => src/cemu}/plugins/scratchboard.py (100%) rename {cemu => src/cemu}/settings.py (100%) create mode 100644 src/cemu/shortcuts.py rename {cemu => src/cemu}/styles/default.qss (100%) rename {cemu => src/cemu}/syscalls/linux/aarch64.csv (100%) rename {cemu => src/cemu}/syscalls/linux/arm-thumb.csv (100%) rename {cemu => src/cemu}/syscalls/linux/arm.csv (100%) rename {cemu => src/cemu}/syscalls/linux/mips.csv (100%) rename {cemu => src/cemu}/syscalls/linux/mips64.csv (100%) rename {cemu => src/cemu}/syscalls/linux/sparc.csv (100%) rename {cemu => src/cemu}/syscalls/linux/x86-64.csv (100%) rename {cemu => src/cemu}/syscalls/linux/x86.csv (100%) rename {cemu => src/cemu}/templates/about.html (100%) rename {cemu => src/cemu}/templates/cemu.ini (100%) rename {cemu => src/cemu}/templates/linux/template.asm (100%) rename {cemu => src/cemu}/templates/linux/template.c (100%) rename {cemu => src/cemu}/ui/__init__.py (100%) rename {cemu => src/cemu}/ui/codeeditor.py (94%) rename {cemu => src/cemu}/ui/command.py (91%) rename {cemu => src/cemu}/ui/highlighter.py (100%) rename {cemu => src/cemu}/ui/log.py (100%) rename {cemu => src/cemu}/ui/main.py (91%) rename {cemu => src/cemu}/ui/mapping.py (87%) rename {cemu => src/cemu}/ui/memory.py (94%) rename {cemu => src/cemu}/ui/registers.py (90%) rename {cemu => src/cemu}/ui/utils.py (93%) rename {cemu => src/cemu}/utils.py (96%) diff --git a/.gitignore b/.gitignore index 9c11a1f..d04b87c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,7 @@ __pycache__ .coverage* build dist -/.idea -/.venv +.idea +.venv +CEmu.egg-info +htmlcov diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08abdc4..5be0297 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ -repos: - - repo: https://github.com/psf/black - rev: '23.3.0' - hooks: - - id: black - language_version: python3.10 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.5.5 + hooks: + - id: ruff + args: [ --fix ] + - id: ruff-format diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 8d6c695..0000000 --- a/.pylintrc +++ /dev/null @@ -1,886 +0,0 @@ -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. -extension-pkg-allow-list= - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code. (This is an alternative name to extension-pkg-allow-list -# for backward compatibility.) -extension-pkg-whitelist= - -# Return non-zero exit code if any of these messages/categories are detected, -# even if score is above --fail-under value. Syntax same as enable. Messages -# specified are enabled, while categories only check already-enabled messages. -fail-on= - -# Specify a score threshold to be exceeded before program exits with error. -fail-under=10.0 - -# Files or directories to be skipped. They should be base names, not paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the ignore-list. The -# regex matches against paths and can be in Posix or Windows format. -ignore-paths= - -# Files or directories matching the regex patterns are skipped. The regex -# matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the -# number of processors available to use. -jobs=0 - -# Control the amount of potential inferred values when inferring a single -# object. This can help the performance when dealing with large functions or -# complex, nested conditions. -limit-inference-results=100 - -# List of plugins (as comma separated values of python module names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Minimum Python version to use for version dependent checks. Will default to -# the version used to run pylint. -py-version=3.6 - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once). You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use "--disable=all --enable=classes -# --disable=W". -; disable=invalid-name, -; disallowed-name, -; empty-docstring, -; missing-module-docstring, -; missing-class-docstring, -; missing-function-docstring, -; unidiomatic-typecheck, -; non-ascii-name, -; consider-using-enumerate, -; consider-iterating-dictionary, -; bad-classmethod-argument, -; bad-mcs-method-argument, -; bad-mcs-classmethod-argument, -; single-string-used-for-slots, -; consider-using-dict-items, -; use-maxsplit-arg, -; use-sequence-for-iteration, -; too-many-lines, -; missing-final-newline, -; trailing-newlines, -; superfluous-parens, -; mixed-line-endings, -; unexpected-line-ending-format, -; wrong-spelling-in-comment, -; wrong-spelling-in-docstring, -; invalid-characters-in-docstring, -; multiple-imports, -; wrong-import-order, -; ungrouped-imports, -; wrong-import-position, -; useless-import-alias, -; import-outside-toplevel, -; use-implicit-booleaness-not-len, -; use-implicit-booleaness-not-comparison, -; raw-checker-failed, -; bad-inline-option, -; locally-disabled, -; file-ignored, -; suppressed-message, -; useless-suppression, -; deprecated-pragma, -; use-symbolic-message-instead, -; c-extension-no-member, -; literal-comparison, -; comparison-with-itself, -; no-self-use, -; no-classmethod-decorator, -; no-staticmethod-decorator, -; useless-object-inheritance, -; property-with-parameters, -; cyclic-import, -; consider-using-from-import, -; duplicate-code, -; too-many-ancestors, -; too-many-instance-attributes, -; too-few-public-methods, -; too-many-public-methods, -; too-many-return-statements, -; too-many-branches, -; too-many-arguments, -; too-many-locals, -; too-many-statements, -; too-many-boolean-expressions, -; consider-merging-isinstance, -; too-many-nested-blocks, -; simplifiable-if-statement, -; redefined-argument-from-local, -; no-else-return, -; consider-using-ternary, -; trailing-comma-tuple, -; stop-iteration-return, -; simplify-boolean-expression, -; inconsistent-return-statements, -; useless-return, -; consider-swap-variables, -; consider-using-join, -; consider-using-in, -; consider-using-get, -; chained-comparison, -; consider-using-dict-comprehension, -; consider-using-set-comprehension, -; simplifiable-if-expression, -; no-else-raise, -; unnecessary-comprehension, -; consider-using-sys-exit, -; no-else-break, -; no-else-continue, -; super-with-arguments, -; simplifiable-condition, -; condition-evals-to-constant, -; consider-using-generator, -; use-a-generator, -; consider-using-min-builtin, -; consider-using-max-builtin, -; consider-using-with, -; unnecessary-dict-index-lookup, -; use-list-literal, -; use-dict-literal, -; pointless-statement, -; pointless-string-statement, -; expression-not-assigned, -; unnecessary-pass, -; unnecessary-lambda, -; assign-to-new-keyword, -; useless-else-on-loop, -; exec-used, -; eval-used, -; confusing-with-statement, -; using-constant-test, -; missing-parentheses-for-call-in-test, -; self-assigning-variable, -; redeclared-assigned-name, -; assert-on-string-literal, -; comparison-with-callable, -; lost-exception, -; nan-comparison, -; assert-on-tuple, -; attribute-defined-outside-init, -; bad-staticmethod-argument, -; protected-access, -; arguments-differ, -; signature-differs, -; abstract-method, -; super-init-not-called, -; no-init, -; non-parent-init-called, -; useless-super-delegation, -; invalid-overridden-method, -; arguments-renamed, -; unused-private-member, -; overridden-final-method, -; subclassed-final-class, -; bad-indentation, -; wildcard-import, -; deprecated-module, -; reimported, -; import-self, -; preferred-module, -; misplaced-future, -; fixme, -; global-variable-undefined, -; global-statement, -; global-at-module-level, -; unused-argument, -; unused-wildcard-import, -; redefined-outer-name, -; redefined-builtin, -; undefined-loop-variable, -; unbalanced-tuple-unpacking, -; cell-var-from-loop, -; possibly-unused-variable, -; self-cls-assignment, -; bare-except, -; broad-except, -; duplicate-except, -; try-except-raise, -; raise-missing-from, -; raising-format-tuple, -; wrong-exception-operation, -; keyword-arg-before-vararg, -; arguments-out-of-order, -; non-str-assignment-to-dunder-name, -; isinstance-second-argument-not-valid-type, -; logging-not-lazy, -; logging-format-interpolation, -; logging-fstring-interpolation, -; bad-format-string-key, -; unused-format-string-key, -; missing-format-argument-key, -; unused-format-string-argument, -; format-combined-specification, -; missing-format-attribute, -; invalid-format-index, -; duplicate-string-formatting-argument, -; f-string-without-interpolation, -; useless-with-lock - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -; enable=unneeded-not, -; format-string-without-interpolation, -; anomalous-unicode-escape-in-string, -; implicit-str-concat, -; inconsistent-quotes, -; redundant-u-string-prefix, -; boolean-datetime, -; redundant-unittest-assert, -; deprecated-method, -; bad-thread-instantiation, -; shallow-copy-environ, -; invalid-envvar-default, -; subprocess-popen-preexec-fn, -; subprocess-run-check, -; deprecated-argument, -; deprecated-class, -; deprecated-decorator, -; unspecified-encoding, -; forgotten-debug-statement, -; using-f-string-in-unsupported-version, -; using-final-decorator-in-unsupported-version, -; singleton-comparison, -; consider-using-f-string, -; line-too-long, -; trailing-whitespace, -; multiple-statements, -; syntax-error, -; unrecognized-inline-option, -; bad-option-value, -; bad-plugin-value, -; bad-configuration-section, -; init-is-generator, -; return-in-init, -; function-redefined, -; not-in-loop, -; return-outside-function, -; yield-outside-function, -; return-arg-in-generator, -; nonexistent-operator, -; duplicate-argument-name, -; abstract-class-instantiated, -; bad-reversed-sequence, -; too-many-star-expressions, -; invalid-star-assignment-target, -; star-needs-assignment-target, -; nonlocal-and-global, -; continue-in-finally, -; nonlocal-without-binding, -; used-prior-global-declaration, -; misplaced-format-function, -; method-hidden, -; access-member-before-definition, -; no-method-argument, -; no-self-argument, -; invalid-slots-object, -; assigning-non-slot, -; invalid-slots, -; inherit-non-class, -; inconsistent-mro, -; duplicate-bases, -; class-variable-slots-conflict, -; invalid-class-object, -; non-iterator-returned, -; unexpected-special-method-signature, -; invalid-length-returned, -; invalid-bool-returned, -; invalid-index-returned, -; invalid-repr-returned, -; invalid-str-returned, -; invalid-bytes-returned, -; invalid-hash-returned, -; invalid-length-hint-returned, -; invalid-format-returned, -; invalid-getnewargs-returned, -; invalid-getnewargs-ex-returned, -; import-error, -; relative-beyond-top-level, -; used-before-assignment, -; undefined-variable, -; undefined-all-variable, -; invalid-all-object, -; invalid-all-format, -; no-name-in-module, -; unpacking-non-sequence, -; bad-except-order, -; raising-bad-type, -; bad-exception-context, -; misplaced-bare-raise, -; raising-non-exception, -; notimplemented-raised, -; catching-non-exception, -; bad-super-call, -; no-member, -; not-callable, -; assignment-from-no-return, -; no-value-for-parameter, -; too-many-function-args, -; unexpected-keyword-arg, -; redundant-keyword-arg, -; missing-kwoa, -; invalid-sequence-index, -; invalid-slice-index, -; assignment-from-none, -; not-context-manager, -; invalid-unary-operand-type, -; unsupported-binary-operation, -; repeated-keyword, -; not-an-iterable, -; not-a-mapping, -; unsupported-membership-test, -; unsubscriptable-object, -; unsupported-assignment-operation, -; unsupported-delete-operation, -; invalid-metaclass, -; unhashable-dict-key, -; dict-iter-missing-items, -; await-outside-async, -; logging-unsupported-format, -; logging-format-truncated, -; logging-too-many-args, -; logging-too-few-args, -; bad-format-character, -; truncated-format-string, -; mixed-format-string, -; format-needs-mapping, -; missing-format-string-key, -; too-many-format-args, -; too-few-format-args, -; bad-string-format-type, -; bad-str-strip-call, -; invalid-envvar-value, -; yield-inside-async-function, -; not-async-context-manager, -; fatal, -; astroid-error, -; parse-error, -; config-parse-error, -; method-check-failed, -; unreachable, -; dangerous-default-value, -; duplicate-key, -; unnecessary-semicolon, -; global-variable-not-assigned, -; unused-import, -; unused-variable, -; binary-op-exception, -; bad-format-string, -; anomalous-backslash-in-string, -; bad-open-mode - -enable = F,E,unreachable,duplicate-key,unnecessary-semicolon,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode,dangerous-default-value,trailing-whitespace,unneeded-not,singleton-comparison,unused-import,line-too-long,multiple-statements,consider-using-f-string,global-variable-not-assigned -disable = all - -[REPORTS] - -# Python expression which should return a score less than or equal to 10. You -# have access to the variables 'error', 'warning', 'refactor', and 'convention' -# which contain the number of messages in each category, as well as 'statement' -# which is the total number of statements analyzed. This score is used by the -# global evaluation report (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details. -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio). You can also give a reporter class, e.g. -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages. -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - -# Complete name of functions that never returns. When checking for -# inconsistent-return-statements if a never returning function is called then -# it will be considered as an explicit return statement and no message will be -# printed. -never-returning-functions=sys.exit,argparse.parse_error - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format=LF - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Maximum number of characters on a single line. -max-line-length=200 - -# Maximum number of lines in a module. -max-module-lines=15000 - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[SPELLING] - -# Limits count of emitted suggestions for spelling mistakes. -max-spelling-suggestions=4 - -# Spelling dictionary name. Available dictionaries: none. To make it work, -# install the 'python-enchant' package. -spelling-dict= - -# List of comma separated words that should be considered directives if they -# appear and the beginning of a comment and should not be checked. -spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains the private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to the private dictionary (see the -# --spelling-private-dict-file option) instead of raising a message. -spelling-store-unknown-words=no - - -[LOGGING] - -# The type of string formatting that logging methods do. `old` means using % -# formatting, `new` is for `{}` formatting. -logging-format-style=old - -# Logging modules to check that the string format arguments are in logging -# function parameter format. -logging-modules=logging - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid defining new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of names allowed to shadow builtins -allowed-redefined-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_, - _cb - -# A regular expression matching the name of dummy variables (i.e. expected to -# not be used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore. -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io - - -[SIMILARITIES] - -# Comments are removed from the similarity computation -ignore-comments=yes - -# Docstrings are removed from the similarity computation -ignore-docstrings=yes - -# Imports are removed from the similarity computation -ignore-imports=no - -# Signatures are removed from the similarity computation -ignore-signatures=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - -# Regular expression of note tags to take in consideration. -#notes-rgx= - - -[BASIC] - -# Naming style matching correct argument names. -argument-naming-style=snake_case - -# Regular expression matching correct argument names. Overrides argument- -# naming-style. -#argument-rgx= - -# Naming style matching correct attribute names. -attr-naming-style=snake_case - -# Regular expression matching correct attribute names. Overrides attr-naming- -# style. -#attr-rgx= - -# Bad variable names which should always be refused, separated by a comma. -bad-names=foo, - bar, - baz, - toto, - tutu, - tata - -# Bad variable names regexes, separated by a comma. If names match any regex, -# they will always be refused -bad-names-rgxs= - -# Naming style matching correct class attribute names. -class-attribute-naming-style=any - -# Regular expression matching correct class attribute names. Overrides class- -# attribute-naming-style. -#class-attribute-rgx= - -# Naming style matching correct class constant names. -class-const-naming-style=UPPER_CASE - -# Regular expression matching correct class constant names. Overrides class- -# const-naming-style. -#class-const-rgx= - -# Naming style matching correct class names. -class-naming-style=PascalCase - -# Regular expression matching correct class names. Overrides class-naming- -# style. -#class-rgx= - -# Naming style matching correct constant names. -const-naming-style=UPPER_CASE - -# Regular expression matching correct constant names. Overrides const-naming- -# style. -#const-rgx= - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming style matching correct function names. -function-naming-style=snake_case - -# Regular expression matching correct function names. Overrides function- -# naming-style. -#function-rgx= - -# Good variable names which should always be accepted, separated by a comma. -good-names=i, - j, - k, - ex, - Run, - _ - -# Good variable names regexes, separated by a comma. If names match any regex, -# they will always be accepted -good-names-rgxs= - -# Include a hint for the correct naming format with invalid-name. -include-naming-hint=no - -# Naming style matching correct inline iteration names. -inlinevar-naming-style=any - -# Regular expression matching correct inline iteration names. Overrides -# inlinevar-naming-style. -#inlinevar-rgx= - -# Naming style matching correct method names. -method-naming-style=snake_case - -# Regular expression matching correct method names. Overrides method-naming- -# style. -#method-rgx= - -# Naming style matching correct module names. -module-naming-style=snake_case - -# Regular expression matching correct module names. Overrides module-naming- -# style. -#module-rgx= - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -# These decorators are taken in consideration only for invalid-name. -property-classes=abc.abstractproperty - -# Naming style matching correct variable names. -variable-naming-style=snake_case - -# Regular expression matching correct variable names. Overrides variable- -# naming-style. -#variable-rgx= - - -[STRING] - -# This flag controls whether inconsistent-quotes generates a warning when the -# character used as a quote delimiter is used inconsistently within a module. -check-quote-consistency=no - -# This flag controls whether the implicit-str-concat should generate a warning -# on implicit string concatenation in sequences defined over several lines. -check-str-concat-over-line-jumps=no - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# class is considered mixin if its name matches the mixin-class-rgx option. -ignore-mixin-members=yes - -# Tells whether to warn about missing members when the owner of the attribute -# is inferred to be None. -ignore-none=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis). It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - -# Regex pattern to define which classes are considered mixins ignore-mixin- -# members is set to 'yes' -mixin-class-rgx=.*[Mm]ixin - -# List of decorators that change the signature of a decorated function. -signature-mutators= - - -[IMPORTS] - -# List of modules that can be imported at any level, not just the top level -# one. -allow-any-import-level= - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma. -deprecated-modules= - -# Output a graph (.gv or any supported image format) of external dependencies -# to the given file (report RP0402 must not be disabled). -ext-import-graph= - -# Output a graph (.gv or any supported image format) of all (i.e. internal and -# external) dependencies to the given file (report RP0402 must not be -# disabled). -import-graph= - -# Output a graph (.gv or any supported image format) of internal dependencies -# to the given file (report RP0402 must not be disabled). -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - -# Couples of modules and preferred modules, separated by a comma. -preferred-modules= - - -[DESIGN] - -# List of regular expressions of class ancestor names to ignore when counting -# public methods (see R0903) -exclude-too-few-public-methods= - -# List of qualified class names to ignore when counting class parents (see -# R0901) -ignored-parents= - -# Maximum number of arguments for function / method. -max-args=5 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Maximum number of boolean expressions in an if statement (see R0916). -max-bool-expr=5 - -# Maximum number of branch for function / method body. -max-branches=12 - -# Maximum number of locals for function / method body. -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body. -max-returns=6 - -# Maximum number of statements in function / method body. -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[CLASSES] - -# Warn about protected attribute access inside special methods -check-protected-access-in-special-methods=no - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__, - __new__, - setUp, - __post_init__ - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=cls - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "BaseException, Exception". -overgeneral-exceptions=BaseException, - Exception diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..7c7a975 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.10 \ No newline at end of file diff --git a/README.md b/README.md index f95714e..7aaa173 100644 --- a/README.md +++ b/README.md @@ -77,8 +77,8 @@ python -m cemu This should produce a GUI similar to this: -![cemu-gui](images/screenshots/cemu-windows-light.png) -![cemu-gui](images/screenshots/cemu-windows-dark.png) +![cemu-gui](cemu/img/cemu-windows-light.png) +![cemu-gui](cemu/img/cemu-windows-dark.png) ### In the terminal diff --git a/cemu/shortcuts.py b/cemu/shortcuts.py deleted file mode 100644 index 72baea5..0000000 --- a/cemu/shortcuts.py +++ /dev/null @@ -1,55 +0,0 @@ -import cemu.core - -SHORTCUT_CONFIG_SECTION_NAME = "Shortcuts" - - -class ShortcutManager: - def __init__(self, *args, **kwargs): - self._defaults: dict[str, tuple[str, str]] = { - # fmt: off - # menubar - "exit_application": ("Alt+F4", "Exit the application"), - "generate_asm_file": ("", "Save the content as a compilable Assembly file."), - "generate_c_file": ("", "Save the content as a compilable C file."), - "save_as_binary": ("Ctrl+N", "Save the content of the raw binary pane in a file."), - "save_as_asm": ("Ctrl+S", "Save the content of the assembly pane in a file."), - "load_binary": ("Ctrl+B", "Load a raw binary file."), - "load_assembly": ("Ctrl+O", "Load an assembly file."), - "shortcut_popup": ("Ctrl+P", "Show the Shortcut bindings"), - "about_popup": ("", "Generic information about CEMU"), - "generate_pe_exe": ("", "Build a valid Windows PE executable"), - "generate_elf_exe": ("", "Build a valid Linux ELF executable"), - "toggle_focus_mode": ("Ctrl+F", "Toggle focus mode"), - - # emulator - "emulator_check": ("Alt+C", "Check the assembly code from the assembly pane"), - "emulator_run_all": ("Alt+R", "Check and run the assembly code"), - "emulator_step": ("Alt+S", "Starts emulation by stepping into it"), - "emulator_stop": ("Alt+X", "Stop emulation"), - "emulator_reset": ("", "Reset emulator"), - # fmt: on - } - - self._config: dict[str, tuple[str, str]] = {} - self.load() - return - - def shortcut(self, attr: str) -> str: - return self._config[attr][0] - - def description(self, attr) -> str: - return self._config[attr][1] - - def load(self) -> bool: - """ - Load the shortcuts dict from either the config file if the value exists, or - the defaults - """ - settings = cemu.core.context.settings - for key in self._defaults: - default_shortcut, description = self._defaults[key] - value = settings.get(SHORTCUT_CONFIG_SECTION_NAME, key, default_shortcut) - settings.set(SHORTCUT_CONFIG_SECTION_NAME, key, value) - self._config[key] = (value, description) - - return True diff --git a/pyproject.toml b/pyproject.toml index fae5e51..1bf1d39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,6 @@ - -# -# https://packaging.python.org/en/latest/tutorials/packaging-projects -# -[build-system] -requires = ["setuptools>=61.0"] -build-backend = "setuptools.build_meta" - - [project] name = "CEmu" -version = "0.8" +version = "0.8.0" authors = [{ name = "hugsy", email = "hugsy@blah.cat" }] description = "Cemu is a simple assembly/dissembly/emulation IDE that provides an easy Plug-n-Play environment to start playing with many architectures (currently supports x86-{32,64}, ARM, AARCH64, MIPS, MIPS64, SPARC and PPC)." readme = "README.md" @@ -23,7 +14,6 @@ classifiers = [ "Natural Language :: English", "Environment :: Console", ] - keywords = [ "assembly", "disassembly", @@ -38,35 +28,40 @@ keywords = [ ] dependencies = [ - "capstone", - "unicorn", - "keystone-engine", - "Pygments", - "lief", - "loguru", - "prompt_toolkit", - "PyQt6", + "capstone>=5.0.1", + "unicorn>=2.0.1.post1", + "keystone-engine>=0.9.2", + "pygments>=2.18.0", + "lief>=0.15.1", + "loguru>=0.7.2", + "prompt-toolkit>=3.0.47", + "pyqt6>=6.7.1", + "setuptools>=72.1.0", ] -[project.optional-dependencies] -dev = ["pre-commit", "debugpy", "black"] - -tests = [ - "pytest", - "pytest-cov", - "pytest-xdist", - "pytest-benchmark", - "pytest-forked", - "coverage", +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.rye] +managed = true +dev-dependencies = [ + "pytest>=8.3.2", + "pytest-cov>=5.0.0", + "coverage>=7.6.0", + "debugpy>=1.8.2", ] -all = ["cemu[dev,tests]"] +[tool.hatch.metadata] +allow-direct-references = true +[tool.hatch.build.targets.wheel] +packages = ["src/cemu"] -[project.entry-points.console_scripts] +[project.scripts] cemu = "cemu.__main__:main" -[project.entry-points.gui_scripts] +[project.gui-scripts] cemu = "cemu.__main__:main" [project.urls] @@ -77,18 +72,30 @@ cemu = "cemu.__main__:main" minversion = "6.0" python_functions = ["test_*", "time_*"] python_files = ["*.py"] -log_cli = true +log_cli = false log_cli_level = "DEBUG" log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)" log_cli_date_format = "%Y-%m-%d %H:%M:%S" -addopts = "--cov --cov-report html --cov-report term-missing --cov-fail-under 45" +# addopts = "--cov --cov-report html --cov-report term-missing --cov-fail-under 45" testpaths = ["tests"] pythonpath = ["."] +filterwarnings = [ + "error", + "ignore::DeprecationWarning", + # `unicorn` uses `pkg_resources` which is deprecated, ignore the warning + 'ignore:.*_pytest\\assertion\\rewrite.py.*', +] + [tool.isort] profile = "black" [tool.ruff] +target-version = "py310" +line-length = 140 + +[tool.ruff.lint] +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" select = ["E", "F"] ignore = [] fixable = [ @@ -138,7 +145,6 @@ fixable = [ "YTT", ] unfixable = [] - exclude = [ ".bzr", ".direnv", @@ -163,9 +169,5 @@ exclude = [ "venv", ] -line-length = 120 -dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" -target-version = "py310" - -[tool.ruff.mccabe] +[tool.ruff.lint.mccabe] max-complexity = 10 diff --git a/requirements-dev.lock b/requirements-dev.lock new file mode 100644 index 0000000..3d311f9 --- /dev/null +++ b/requirements-dev.lock @@ -0,0 +1,58 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +capstone==5.0.1 + # via cemu +colorama==0.4.6 + # via loguru + # via pytest +coverage==7.6.0 + # via pytest-cov +debugpy==1.8.2 +exceptiongroup==1.2.2 + # via pytest +iniconfig==2.0.0 + # via pytest +keystone-engine==0.9.2 + # via cemu +lief==0.15.1 + # via cemu +loguru==0.7.2 + # via cemu +packaging==24.1 + # via pytest +pluggy==1.5.0 + # via pytest +prompt-toolkit==3.0.47 + # via cemu +pygments==2.18.0 + # via cemu +pyqt6==6.7.1 + # via cemu +pyqt6-qt6==6.7.2 + # via pyqt6 +pyqt6-sip==13.8.0 + # via pyqt6 +pytest==8.3.2 + # via pytest-cov +pytest-cov==5.0.0 +setuptools==72.1.0 + # via cemu +tomli==2.0.1 + # via coverage + # via pytest +unicorn==2.0.1.post1 + # via cemu +wcwidth==0.2.13 + # via prompt-toolkit +win32-setctime==1.1.0 + # via loguru diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 0000000..d92419e --- /dev/null +++ b/requirements.lock @@ -0,0 +1,40 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +capstone==5.0.1 + # via cemu +colorama==0.4.6 + # via loguru +keystone-engine==0.9.2 + # via cemu +lief==0.15.1 + # via cemu +loguru==0.7.2 + # via cemu +prompt-toolkit==3.0.47 + # via cemu +pygments==2.18.0 + # via cemu +pyqt6==6.7.1 + # via cemu +pyqt6-qt6==6.7.2 + # via pyqt6 +pyqt6-sip==13.8.0 + # via pyqt6 +setuptools==72.1.0 + # via cemu +unicorn==2.0.1.post1 + # via cemu +wcwidth==0.2.13 + # via prompt-toolkit +win32-setctime==1.1.0 + # via loguru diff --git a/cemu/__init__.py b/src/cemu/__init__.py similarity index 100% rename from cemu/__init__.py rename to src/cemu/__init__.py diff --git a/cemu/__main__.py b/src/cemu/__main__.py similarity index 51% rename from cemu/__main__.py rename to src/cemu/__main__.py index 6babc41..c8cf38b 100644 --- a/cemu/__main__.py +++ b/src/cemu/__main__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 +import argparse import pathlib -import sys import os import cemu.const @@ -19,26 +19,33 @@ def setup_remote_debug(port: int = cemu.const.DEBUG_DEBUGPY_PORT): cemu.log.dbg("Client connected, resuming session") -def main(): - if bool(os.getenv("DEBUG", False)) or "--debug" in sys.argv: +def main(argv: list[str]): + parser = argparse.ArgumentParser( + prog=cemu.const.PROGNAME, + description=cemu.const.DESCRIPTION) + parser.add_argument("filename") + parser.add_argument("--debug", action="store_true") + parser.add_argument("--attach", action="store_true") + parser.add_argument("--cli", action="store_true") + args = parser.parse_args(argv) + + if bool(os.getenv("DEBUG", False)) or args.debug: cemu.const.DEBUG = True if cemu.const.DEBUG: cemu.log.register_sink(print) cemu.log.dbg("Starting in Debug Mode") - - if "--attach" in sys.argv: + if args.attach: setup_remote_debug() - if "--cli" in sys.argv: - cemu.core.CemuCli(sys.argv) - return - - cemu.core.CemuGui(sys.argv) - return + if args.cli: + cemu.core.CemuCli(args) + else: + cemu.core.CemuGui() if __name__ == "__main__": + import sys path = pathlib.Path(__file__).absolute().parent.parent sys.path.append(str(path)) - main() + main(sys.argv) diff --git a/cemu/arch/__init__.py b/src/cemu/arch/__init__.py similarity index 95% rename from cemu/arch/__init__.py rename to src/cemu/arch/__init__.py index df662d2..fdf0db5 100644 --- a/cemu/arch/__init__.py +++ b/src/cemu/arch/__init__.py @@ -90,20 +90,14 @@ def syscalls(self): row = [x.strip() for x in row.strip().split(",")] syscall_number = int(row[0]) syscall_name = row[1].lower() - self.__syscalls[syscall_name] = ( - self.syscall_base + syscall_number - ) + self.__syscalls[syscall_name] = self.syscall_base + syscall_number return self.__syscalls def __eq__(self, x): if not isinstance(x, Architecture): return False - return ( - self.name == x.name - and self.endianness == x.endianness - and self.syntax == x.syntax - ) + return self.name == x.name and self.endianness == x.endianness and self.syntax == x.syntax def unicorn(self) -> tuple[int, int, int]: """Returns a tuple with the values of unicorn architecture, mode, endianess diff --git a/cemu/arch/arm.py b/src/cemu/arch/arm.py similarity index 99% rename from cemu/arch/arm.py rename to src/cemu/arch/arm.py index 9fa7a4a..fdc4ee5 100644 --- a/cemu/arch/arm.py +++ b/src/cemu/arch/arm.py @@ -29,7 +29,6 @@ class ARM(Architecture): pc, sp, ] - syscall_filename = "arm" def __init__(self, *args, **kwargs): self.thumb = kwargs.get("thumb", False) diff --git a/cemu/arch/generic.py b/src/cemu/arch/generic.py similarity index 100% rename from cemu/arch/generic.py rename to src/cemu/arch/generic.py diff --git a/cemu/arch/mips.py b/src/cemu/arch/mips.py similarity index 69% rename from cemu/arch/mips.py rename to src/cemu/arch/mips.py index aa4b9ec..de70f11 100644 --- a/cemu/arch/mips.py +++ b/src/cemu/arch/mips.py @@ -58,27 +58,21 @@ def keystone(self) -> tuple[int, int, int]: return ( keystone.KS_ARCH_MIPS, keystone.KS_MODE_MIPS32, - keystone.KS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else keystone.KS_MODE_BIG_ENDIAN, + keystone.KS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else keystone.KS_MODE_BIG_ENDIAN, ) def capstone(self) -> tuple[int, int, int]: return ( capstone.CS_ARCH_MIPS, capstone.CS_MODE_MIPS32, - capstone.CS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else capstone.CS_MODE_BIG_ENDIAN, + capstone.CS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else capstone.CS_MODE_BIG_ENDIAN, ) def unicorn(self) -> tuple[int, int, int]: return ( unicorn.UC_ARCH_MIPS, unicorn.UC_MODE_MIPS32, - unicorn.UC_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else unicorn.UC_MODE_BIG_ENDIAN, + unicorn.UC_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else unicorn.UC_MODE_BIG_ENDIAN, ) def uc_register(self, name: str) -> int: @@ -94,25 +88,19 @@ def keystone(self) -> tuple[int, int, int]: return ( keystone.KS_ARCH_MIPS, keystone.KS_MODE_MIPS64, - keystone.KS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else keystone.KS_MODE_BIG_ENDIAN, + keystone.KS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else keystone.KS_MODE_BIG_ENDIAN, ) def capstone(self) -> tuple[int, int, int]: return ( capstone.CS_ARCH_MIPS, capstone.CS_MODE_MIPS64, - capstone.CS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else capstone.CS_MODE_BIG_ENDIAN, + capstone.CS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else capstone.CS_MODE_BIG_ENDIAN, ) def unicorn(self) -> tuple[int, int, int]: return ( unicorn.UC_ARCH_MIPS, unicorn.UC_MODE_MIPS64, - unicorn.UC_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else unicorn.UC_MODE_BIG_ENDIAN, + unicorn.UC_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else unicorn.UC_MODE_BIG_ENDIAN, ) diff --git a/cemu/arch/ppc.py b/src/cemu/arch/ppc.py similarity index 100% rename from cemu/arch/ppc.py rename to src/cemu/arch/ppc.py diff --git a/cemu/arch/sparc.py b/src/cemu/arch/sparc.py similarity index 68% rename from cemu/arch/sparc.py rename to src/cemu/arch/sparc.py index e9b81e2..da71607 100644 --- a/cemu/arch/sparc.py +++ b/src/cemu/arch/sparc.py @@ -55,27 +55,21 @@ def keystone(self) -> tuple[int, int, int]: return ( keystone.KS_ARCH_SPARC, keystone.KS_MODE_SPARC32, - keystone.KS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else keystone.KS_MODE_BIG_ENDIAN, + keystone.KS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else keystone.KS_MODE_BIG_ENDIAN, ) def capstone(self) -> tuple[int, int, int]: return ( capstone.CS_ARCH_SPARC, 0, - capstone.CS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else capstone.CS_MODE_BIG_ENDIAN, + capstone.CS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else capstone.CS_MODE_BIG_ENDIAN, ) def unicorn(self) -> tuple[int, int, int]: return ( unicorn.UC_ARCH_SPARC, unicorn.UC_MODE_SPARC32, - unicorn.UC_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else unicorn.UC_MODE_BIG_ENDIAN, + unicorn.UC_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else unicorn.UC_MODE_BIG_ENDIAN, ) def uc_register(self, name: str) -> int: @@ -90,25 +84,19 @@ def keystone(self) -> tuple[int, int, int]: return ( keystone.KS_ARCH_SPARC, keystone.KS_MODE_SPARC64, - keystone.KS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else keystone.KS_MODE_BIG_ENDIAN, + keystone.KS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else keystone.KS_MODE_BIG_ENDIAN, ) def capstone(self) -> tuple[int, int, int]: return ( capstone.CS_ARCH_SPARC, capstone.CS_MODE_64, - capstone.CS_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else capstone.CS_MODE_BIG_ENDIAN, + capstone.CS_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else capstone.CS_MODE_BIG_ENDIAN, ) def unicorn(self) -> tuple[int, int, int]: return ( unicorn.UC_ARCH_SPARC, unicorn.UC_MODE_SPARC64, - unicorn.UC_MODE_LITTLE_ENDIAN - if self.endianness == Endianness.LITTLE_ENDIAN - else unicorn.UC_MODE_BIG_ENDIAN, + unicorn.UC_MODE_LITTLE_ENDIAN if self.endianness == Endianness.LITTLE_ENDIAN else unicorn.UC_MODE_BIG_ENDIAN, ) diff --git a/cemu/arch/x86.py b/src/cemu/arch/x86.py similarity index 94% rename from cemu/arch/x86.py rename to src/cemu/arch/x86.py index 8d1bb73..c9c4db8 100644 --- a/cemu/arch/x86.py +++ b/src/cemu/arch/x86.py @@ -78,13 +78,7 @@ class SegmentDescriptor: P: bool def __int__(self) -> int: - return ( - (self.base) - | (self.type << 8) - | (int(self.S) << 12) - | (self.DPL << 13) - | (int(self.P) << 15) - ) + return (self.base) | (self.type << 8) | (int(self.S) << 12) | (self.DPL << 13) | (int(self.P) << 15) name = "Intel i386 32bit" pc = "EIP" diff --git a/cemu/cli/__init__.py b/src/cemu/cli/__init__.py similarity index 100% rename from cemu/cli/__init__.py rename to src/cemu/cli/__init__.py diff --git a/cemu/cli/repl.py b/src/cemu/cli/repl.py similarity index 90% rename from cemu/cli/repl.py rename to src/cemu/cli/repl.py index a4b197d..df8aadd 100644 --- a/cemu/cli/repl.py +++ b/src/cemu/cli/repl.py @@ -42,9 +42,7 @@ def __init__(self, args): self.keep_running = False self.prompt = "(cemu)> " self.__background_emulator_thread = EmulationRunner() - cemu.core.context.emulator.set_threaded_runner( - self.__background_emulator_thread - ) + cemu.core.context.emulator.set_threaded_runner(self.__background_emulator_thread) # register the callbacks for the emulator emu = cemu.core.context.emulator @@ -137,11 +135,7 @@ def run_forever(self): # line = line[1:] parts = line.split() - command, args = ( - (parts[0].lower(), parts[1:]) - if len(parts) >= 2 - else (parts[0].lower(), []) - ) + command, args = (parts[0].lower(), parts[1:]) if len(parts) >= 2 else (parts[0].lower(), []) else: # # It's assembly, happen and keep looping @@ -169,13 +163,9 @@ def run_forever(self): case "arch": match args[0]: case "get": - print( - f"Current architecture {cemu.core.context.architecture}" - ) + print(f"Current architecture {cemu.core.context.architecture}") case "set": - cemu.core.context.architecture = ( - cemu.arch.Architectures.find(args[1]) - ) + cemu.core.context.architecture = cemu.arch.Architectures.find(args[1]) case "regs": match args[0]: @@ -196,9 +186,7 @@ def run_forever(self): for idx, section in enumerate(emu.sections): print(f"{idx:#04x}\t{section}") case "add": - section = cemu.memory.MemorySection( - args[1], int(args[2], 0), int(args[3], 0), args[4] - ) + section = cemu.memory.MemorySection(args[1], int(args[2], 0), int(args[3], 0), args[4]) emu.sections.append(section) dbg(f"Section {section} added") case "del": @@ -232,9 +220,7 @@ def run_forever(self): error("Assembly code is invalid") case "edit": - with tempfile.NamedTemporaryFile( - suffix=".asm", mode="w+" - ) as f: + with tempfile.NamedTemporaryFile(suffix=".asm", mode="w+") as f: filepath = pathlib.Path(f.name) f.write(emu.codelines) f.flush() @@ -267,9 +253,7 @@ def run_forever(self): return def bottom_toolbar(self) -> str: - return ( - f"{str(cemu.core.context.emulator)} [{str(cemu.core.context.architecture)}]" - ) + return f"{str(cemu.core.context.emulator)} [{str(cemu.core.context.architecture)}]" class EmulationRunner: diff --git a/cemu/const.py b/src/cemu/const.py similarity index 100% rename from cemu/const.py rename to src/cemu/const.py diff --git a/cemu/core.py b/src/cemu/core.py similarity index 87% rename from cemu/core.py rename to src/cemu/core.py index f235093..1e2a7d4 100644 --- a/cemu/core.py +++ b/src/cemu/core.py @@ -3,7 +3,7 @@ import argparse import sys -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Optional, Union import cemu.ui.main @@ -79,7 +79,7 @@ def root(self, root: cemu.ui.main.CEmuWindow): context: Union[GlobalContext, GlobalGuiContext] -def CemuGui(args: list[str]) -> None: +def CemuGui() -> None: """Entry point of the GUI Args: @@ -93,14 +93,14 @@ def CemuGui(args: list[str]) -> None: cemu.log.dbg("Creating GUI context") context = GlobalGuiContext() - app = QApplication(args) + app = QApplication(sys.argv) app.setStyleSheet(cemu.const.DEFAULT_STYLE_PATH.open().read()) app.setWindowIcon(QIcon(str(cemu.const.ICON_PATH.absolute()))) context.root = cemu.ui.main.CEmuWindow(app) sys.exit(app.exec()) -def CemuCli(argv: list[str]) -> None: +def CemuCli(argv: Optional[argparse.Namespace]) -> None: """Entry point of the CLI Args: @@ -117,10 +117,12 @@ def CemuCli(argv: list[str]) -> None: # # Run the REPL with the command line arguments # - args = argparse.ArgumentParser( - prog=cemu.const.PROGNAME, description=cemu.const.DESCRIPTION - ) - args.parse_args(argv) + if argv is None: + args = argparse.ArgumentParser(prog=cemu.const.PROGNAME, description=cemu.const.DESCRIPTION) + args.parse_args(sys.argv) + else: + assert isinstance(argv, argparse.Namespace) + args = argv instance = cemu.cli.repl.CEmuRepl(args) instance.run_forever() diff --git a/cemu/emulator.py b/src/cemu/emulator.py similarity index 92% rename from cemu/emulator.py rename to src/cemu/emulator.py index 4236a4f..29f0c4e 100644 --- a/cemu/emulator.py +++ b/src/cemu/emulator.py @@ -4,7 +4,6 @@ from typing import Any, Callable, Optional import unicorn -from PyQt6.QtWidgets import QMessageBox import cemu.const import cemu.core @@ -61,11 +60,7 @@ def __getitem__(self, key: str) -> int: int: the register value """ emu = cemu.core.context.emulator - if ( - emu.state - in (EmulatorState.RUNNING, EmulatorState.IDLE, EmulatorState.FINISHED) - and key in self.data.keys() - ): + if emu.state in (EmulatorState.RUNNING, EmulatorState.IDLE, EmulatorState.FINISHED) and key in self.data.keys(): val = emu.get_register_value(key) if val is not None: super().__setitem__(key, val) @@ -103,9 +98,7 @@ def reset(self): self.vm = None self.code = b"" self.sections = MEMORY_MAP_DEFAULT_LAYOUT[:] - self.registers = EmulationRegisters( - {name: 0 for name in cemu.core.context.architecture.registers} - ) + self.registers = EmulationRegisters({name: 0 for name in cemu.core.context.architecture.registers}) self.start_addr = 0 self.set(EmulatorState.NOT_RUNNING) return @@ -200,9 +193,7 @@ def __populate_memory(self) -> bool: return False for section in self.sections: - self.vm.mem_map( - section.address, section.size, perms=section.permission.unicorn() - ) + self.vm.mem_map(section.address, section.size, perms=section.permission.unicorn()) msg = f"Mapping {str(section)}" if section.content: @@ -234,9 +225,7 @@ def __populate_vm_registers(self) -> bool: if self.registers[arch.pc] == 0: section = self.find_section(cemu.const.MEMORY_TEXT_SECTION_NAME) self.registers[arch.pc] = section.address - warn( - f"No value specified for PC register, setting to {self.registers[arch.pc]:#x}" - ) + warn(f"No value specified for PC register, setting to {self.registers[arch.pc]:#x}") # # Set the initial SP if unspecified, in the middle of the stack section @@ -244,9 +233,7 @@ def __populate_vm_registers(self) -> bool: if self.registers[arch.sp] == 0: section = self.find_section(MEMORY_STACK_SECTION_NAME) self.registers[arch.sp] = section.address + (section.size // 2) - warn( - f"No value specified for SP register, setting to {self.registers[arch.sp]:#x}" - ) + warn(f"No value specified for SP register, setting to {self.registers[arch.sp]:#x}") # # Populate all the registers for unicorn @@ -280,9 +267,7 @@ def __populate_vm_registers(self) -> bool: self.registers["SS"] = int( x86.X86_32.SegmentDescriptor( stack.address >> 8, - x86.X86_32.SegmentType.Data - | x86.X86_32.SegmentType.Accessed - | x86.X86_32.SegmentType.ExpandDown, + x86.X86_32.SegmentType.Data | x86.X86_32.SegmentType.Accessed | x86.X86_32.SegmentType.ExpandDown, False, 3, True, @@ -325,9 +310,7 @@ def __generate_text_bytecode(self) -> bool: Returns: bool True if all went well, False otherwise. """ - dbg( - f"[vm::setup] Generating assembly code for {cemu.core.context.architecture.name}" - ) + dbg(f"[vm::setup] Generating assembly code for {cemu.core.context.architecture.name}") try: insns = cemu.utils.assemble(self.codelines, base_address=self.start_addr) @@ -369,9 +352,7 @@ def __populate_text_section(self) -> bool: assert isinstance(self.code, bytes) - dbg( - f"Populated text section {text_section} with {len(self.code)} compiled bytes" - ) + dbg(f"Populated text section {text_section} with {len(self.code)} compiled bytes") self.vm.mem_write(text_section.address, self.code) return True @@ -384,9 +365,7 @@ def next_instruction(self, code: bytes, addr: int) -> Optional[cemu.utils.Instru return None - def hook_code( - self, emu: unicorn.Uc, address: int, size: int, user_data: Any - ) -> bool: + def hook_code(self, emu: unicorn.Uc, address: int, size: int, user_data: Any) -> bool: """ Unicorn instruction hook """ @@ -534,9 +513,7 @@ def set(self, new_state: EmulatorState): info(f"Emulator is now {new_state.name}") self.state = new_state - dbg( - f"Executing {len(self.__state_change_callbacks[new_state])} callbacks for state {new_state.name}" - ) + dbg(f"Executing {len(self.__state_change_callbacks[new_state])} callbacks for state {new_state.name}") # # Notify the components who've subscribed to the new state change @@ -552,9 +529,7 @@ def set(self, new_state: EmulatorState): # This will effectively trigger the execution in unicorn # assert self.threaded_runner, "No threaded runner defined" - assert callable( - getattr(self.threaded_runner, "run") - ), "Threaded runner is not runnable" + assert callable(getattr(self.threaded_runner, "run")), "Threaded runner is not runnable" self.threaded_runner.run() # type: ignore case EmulatorState.TEARDOWN: diff --git a/cemu/errors.py b/src/cemu/errors.py similarity index 100% rename from cemu/errors.py rename to src/cemu/errors.py diff --git a/cemu/examples/aarch64_execve_bin_sh.asm b/src/cemu/examples/aarch64_execve_bin_sh.asm similarity index 100% rename from cemu/examples/aarch64_execve_bin_sh.asm rename to src/cemu/examples/aarch64_execve_bin_sh.asm diff --git a/cemu/examples/arm_nops.raw b/src/cemu/examples/arm_nops.raw similarity index 100% rename from cemu/examples/arm_nops.raw rename to src/cemu/examples/arm_nops.raw diff --git a/cemu/examples/arm_sys_exec_bin_sh.asm b/src/cemu/examples/arm_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/arm_sys_exec_bin_sh.asm rename to src/cemu/examples/arm_sys_exec_bin_sh.asm diff --git a/cemu/examples/mips_sys_exec_bin_sh.asm b/src/cemu/examples/mips_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/mips_sys_exec_bin_sh.asm rename to src/cemu/examples/mips_sys_exec_bin_sh.asm diff --git a/cemu/examples/mipsbe_sys_exec_bin_sh.asm b/src/cemu/examples/mipsbe_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/mipsbe_sys_exec_bin_sh.asm rename to src/cemu/examples/mipsbe_sys_exec_bin_sh.asm diff --git a/cemu/examples/sparc64_sys_exec_bin_sh.asm b/src/cemu/examples/sparc64_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/sparc64_sys_exec_bin_sh.asm rename to src/cemu/examples/sparc64_sys_exec_bin_sh.asm diff --git a/cemu/examples/sparc_nops.raw b/src/cemu/examples/sparc_nops.raw similarity index 100% rename from cemu/examples/sparc_nops.raw rename to src/cemu/examples/sparc_nops.raw diff --git a/cemu/examples/sparc_sys_exec_bin_sh.asm b/src/cemu/examples/sparc_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/sparc_sys_exec_bin_sh.asm rename to src/cemu/examples/sparc_sys_exec_bin_sh.asm diff --git a/cemu/examples/x86_32_read_flag_null_free.asm b/src/cemu/examples/x86_32_read_flag_null_free.asm similarity index 100% rename from cemu/examples/x86_32_read_flag_null_free.asm rename to src/cemu/examples/x86_32_read_flag_null_free.asm diff --git a/cemu/examples/x86_32_sys_exec_bin_sh.asm b/src/cemu/examples/x86_32_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/x86_32_sys_exec_bin_sh.asm rename to src/cemu/examples/x86_32_sys_exec_bin_sh.asm diff --git a/cemu/examples/x86_32_sys_exec_bin_sh_null_free.asm b/src/cemu/examples/x86_32_sys_exec_bin_sh_null_free.asm similarity index 100% rename from cemu/examples/x86_32_sys_exec_bin_sh_null_free.asm rename to src/cemu/examples/x86_32_sys_exec_bin_sh_null_free.asm diff --git a/cemu/examples/x86_64_read_flag_null_free.asm b/src/cemu/examples/x86_64_read_flag_null_free.asm similarity index 100% rename from cemu/examples/x86_64_read_flag_null_free.asm rename to src/cemu/examples/x86_64_read_flag_null_free.asm diff --git a/cemu/examples/x86_64_sys_exec_bin_sh.asm b/src/cemu/examples/x86_64_sys_exec_bin_sh.asm similarity index 100% rename from cemu/examples/x86_64_sys_exec_bin_sh.asm rename to src/cemu/examples/x86_64_sys_exec_bin_sh.asm diff --git a/cemu/examples/x86_64_sys_exec_bin_sh_null_free.asm b/src/cemu/examples/x86_64_sys_exec_bin_sh_null_free.asm similarity index 100% rename from cemu/examples/x86_64_sys_exec_bin_sh_null_free.asm rename to src/cemu/examples/x86_64_sys_exec_bin_sh_null_free.asm diff --git a/cemu/examples/x86_nops.raw b/src/cemu/examples/x86_nops.raw similarity index 100% rename from cemu/examples/x86_nops.raw rename to src/cemu/examples/x86_nops.raw diff --git a/cemu/exceptions.py b/src/cemu/exceptions.py similarity index 100% rename from cemu/exceptions.py rename to src/cemu/exceptions.py diff --git a/cemu/exports.py b/src/cemu/exports.py similarity index 94% rename from cemu/exports.py rename to src/cemu/exports.py index aca8a7c..f820156 100644 --- a/cemu/exports.py +++ b/src/cemu/exports.py @@ -29,9 +29,7 @@ def parse_as_lief_pe_permission(perm: MemoryPermission, extra: Any = None) -> in return res -def build_pe_executable( - text: bytes, memory_layout: List[MemorySection], arch: Architecture -) -> str: +def build_pe_executable(text: bytes, memory_layout: List[MemorySection], arch: Architecture) -> str: """ Uses LIEF to build a standalone binary. @@ -112,8 +110,6 @@ def build_pe_executable( return outfile -def build_elf_executable( - asm_code: bytes, memory_layout: List[MemorySection], arch: Architecture -) -> str: +def build_elf_executable(asm_code: bytes, memory_layout: List[MemorySection], arch: Architecture) -> str: """ """ raise NotImplementedError("ELF generation will be implemented soon") diff --git a/images/screenshots/cemu-windows-dark.png b/src/cemu/img/cemu-windows-dark.png similarity index 100% rename from images/screenshots/cemu-windows-dark.png rename to src/cemu/img/cemu-windows-dark.png diff --git a/images/screenshots/cemu-windows-light.png b/src/cemu/img/cemu-windows-light.png similarity index 100% rename from images/screenshots/cemu-windows-light.png rename to src/cemu/img/cemu-windows-light.png diff --git a/cemu/img/icon.png b/src/cemu/img/icon.png similarity index 100% rename from cemu/img/icon.png rename to src/cemu/img/icon.png diff --git a/cemu/img/new_logo.png b/src/cemu/img/new_logo.png similarity index 100% rename from cemu/img/new_logo.png rename to src/cemu/img/new_logo.png diff --git a/cemu/log.py b/src/cemu/log.py similarity index 100% rename from cemu/log.py rename to src/cemu/log.py diff --git a/cemu/memory.py b/src/cemu/memory.py similarity index 92% rename from cemu/memory.py rename to src/cemu/memory.py index faf1676..de04f6c 100644 --- a/cemu/memory.py +++ b/src/cemu/memory.py @@ -101,18 +101,10 @@ def from_windows(protect: int) -> "MemoryPermission": return MemoryPermission.EXECUTE | MemoryPermission.READ case 0x40: # PAGE_EXECUTE_READWRITE - return ( - MemoryPermission.READ - | MemoryPermission.WRITE - | MemoryPermission.EXECUTE - ) + return MemoryPermission.READ | MemoryPermission.WRITE | MemoryPermission.EXECUTE case 0x80: # PAGE_EXECUTE_WRITECOPY - return ( - MemoryPermission.READ - | MemoryPermission.WRITE - | MemoryPermission.EXECUTE - ) + return MemoryPermission.READ | MemoryPermission.WRITE | MemoryPermission.EXECUTE case 0x100: raise NotImplementedError("PAGE_GUARD is not implemented") @@ -229,11 +221,7 @@ def content(self) -> Optional[bytes]: return data def __str__(self) -> str: - return ( - f"MemorySection([{self.address:#x}-{self.end:#x}], " - f"name='{self.name:s}', " - f"permission={str(self.permission)})" - ) + return f"MemorySection([{self.address:#x}-{self.end:#x}], " f"name='{self.name:s}', " f"permission={str(self.permission)})" def __contains__(self, addr: int) -> bool: """`in` operator overload diff --git a/cemu/os.py b/src/cemu/os.py similarity index 100% rename from cemu/os.py rename to src/cemu/os.py diff --git a/cemu/plugins/__init__.py b/src/cemu/plugins/__init__.py similarity index 100% rename from cemu/plugins/__init__.py rename to src/cemu/plugins/__init__.py diff --git a/cemu/plugins/pyconsole/__init__.py b/src/cemu/plugins/pyconsole/__init__.py similarity index 100% rename from cemu/plugins/pyconsole/__init__.py rename to src/cemu/plugins/pyconsole/__init__.py diff --git a/cemu/plugins/pyconsole/console.py b/src/cemu/plugins/pyconsole/console.py similarity index 92% rename from cemu/plugins/pyconsole/console.py rename to src/cemu/plugins/pyconsole/console.py index dc82072..08e86ee 100644 --- a/cemu/plugins/pyconsole/console.py +++ b/src/cemu/plugins/pyconsole/console.py @@ -41,9 +41,7 @@ def __init__(self, parent, motd=""): self.setWordWrapMode(QTextOption.WrapMode.WrapAnywhere) self.setUndoRedoEnabled(False) - self.document().setDefaultFont( - QFont(const.DEFAULT_FONT, const.DEFAULT_FONT_SIZE, QFont.Weight.Normal) - ) + self.document().setDefaultFont(QFont(const.DEFAULT_FONT, const.DEFAULT_FONT_SIZE, QFont.Weight.Normal)) self.setText(self.startup_message + os.linesep) self.newPrompt() return @@ -68,13 +66,9 @@ def setCommand(self, command): if self.getCommand() == command: return self.moveCursor(QTextCursor.MoveOperation.End) - self.moveCursor( - QTextCursor.MoveOperation.StartOfLine, QTextCursor.MoveMode.KeepAnchor - ) + self.moveCursor(QTextCursor.MoveOperation.StartOfLine, QTextCursor.MoveMode.KeepAnchor) for i in range(len(self.prompt)): - self.moveCursor( - QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor - ) + self.moveCursor(QTextCursor.MoveOperation.Right, QTextCursor.MoveMode.KeepAnchor) self.textCursor().removeSelectedText() self.textCursor().insertText(command) self.moveCursor(QTextCursor.MoveOperation.End) @@ -200,10 +194,7 @@ def keyPressEvent(self, event): self.setCommand(self.getNextHistoryEntry()) return - if ( - event.key() == Qt.Key.Key_D - and event.modifiers() == Qt.KeyboardModifier.ControlModifier - ): + if event.key() == Qt.Key.Key_D and event.modifiers() == Qt.KeyboardModifier.ControlModifier: self.close() super(PythonConsole, self).keyPressEvent(event) diff --git a/cemu/plugins/scratchboard.py b/src/cemu/plugins/scratchboard.py similarity index 100% rename from cemu/plugins/scratchboard.py rename to src/cemu/plugins/scratchboard.py diff --git a/cemu/settings.py b/src/cemu/settings.py similarity index 100% rename from cemu/settings.py rename to src/cemu/settings.py diff --git a/src/cemu/shortcuts.py b/src/cemu/shortcuts.py new file mode 100644 index 0000000..e607fa6 --- /dev/null +++ b/src/cemu/shortcuts.py @@ -0,0 +1,54 @@ +import cemu.core + +SHORTCUT_CONFIG_SECTION_NAME = "Shortcuts" + + +class ShortcutManager: + def __init__(self, *args, **kwargs): + self._defaults: dict[str, tuple[str, str]] = { + # fmt: off + # menubar + "exit_application": ("Alt+F4", "Exit the application"), + "generate_asm_file": ("", "Save the content as a compilable Assembly file."), + "generate_c_file": ("", "Save the content as a compilable C file."), + "save_as_binary": ("Ctrl+N", "Save the content of the raw binary pane in a file."), + "save_as_asm": ("Ctrl+S", "Save the content of the assembly pane in a file."), + "load_binary": ("Ctrl+B", "Load a raw binary file."), + "load_assembly": ("Ctrl+O", "Load an assembly file."), + "shortcut_popup": ("Ctrl+P", "Show the Shortcut bindings"), + "about_popup": ("", "Generic information about CEMU"), + "generate_pe_exe": ("", "Build a valid Windows PE executable"), + "generate_elf_exe": ("", "Build a valid Linux ELF executable"), + "toggle_focus_mode": ("Ctrl+F", "Toggle focus mode"), + # emulator + "emulator_check": ("Alt+C", "Check the assembly code from the assembly pane"), + "emulator_run_all": ("Alt+R", "Check and run the assembly code"), + "emulator_step": ("Alt+S", "Starts emulation by stepping into it"), + "emulator_stop": ("Alt+X", "Stop emulation"), + "emulator_reset": ("", "Reset emulator"), + # fmt: on + } + + self._config: dict[str, tuple[str, str]] = {} + self.load() + return + + def shortcut(self, attr: str) -> str: + return self._config[attr][0] + + def description(self, attr) -> str: + return self._config[attr][1] + + def load(self) -> bool: + """ + Load the shortcuts dict from either the config file if the value exists, or + the defaults + """ + settings = cemu.core.context.settings + for key in self._defaults: + default_shortcut, description = self._defaults[key] + value = settings.get(SHORTCUT_CONFIG_SECTION_NAME, key, default_shortcut) + settings.set(SHORTCUT_CONFIG_SECTION_NAME, key, value) + self._config[key] = (value, description) + + return True diff --git a/cemu/styles/default.qss b/src/cemu/styles/default.qss similarity index 100% rename from cemu/styles/default.qss rename to src/cemu/styles/default.qss diff --git a/cemu/syscalls/linux/aarch64.csv b/src/cemu/syscalls/linux/aarch64.csv similarity index 100% rename from cemu/syscalls/linux/aarch64.csv rename to src/cemu/syscalls/linux/aarch64.csv diff --git a/cemu/syscalls/linux/arm-thumb.csv b/src/cemu/syscalls/linux/arm-thumb.csv similarity index 100% rename from cemu/syscalls/linux/arm-thumb.csv rename to src/cemu/syscalls/linux/arm-thumb.csv diff --git a/cemu/syscalls/linux/arm.csv b/src/cemu/syscalls/linux/arm.csv similarity index 100% rename from cemu/syscalls/linux/arm.csv rename to src/cemu/syscalls/linux/arm.csv diff --git a/cemu/syscalls/linux/mips.csv b/src/cemu/syscalls/linux/mips.csv similarity index 100% rename from cemu/syscalls/linux/mips.csv rename to src/cemu/syscalls/linux/mips.csv diff --git a/cemu/syscalls/linux/mips64.csv b/src/cemu/syscalls/linux/mips64.csv similarity index 100% rename from cemu/syscalls/linux/mips64.csv rename to src/cemu/syscalls/linux/mips64.csv diff --git a/cemu/syscalls/linux/sparc.csv b/src/cemu/syscalls/linux/sparc.csv similarity index 100% rename from cemu/syscalls/linux/sparc.csv rename to src/cemu/syscalls/linux/sparc.csv diff --git a/cemu/syscalls/linux/x86-64.csv b/src/cemu/syscalls/linux/x86-64.csv similarity index 100% rename from cemu/syscalls/linux/x86-64.csv rename to src/cemu/syscalls/linux/x86-64.csv diff --git a/cemu/syscalls/linux/x86.csv b/src/cemu/syscalls/linux/x86.csv similarity index 100% rename from cemu/syscalls/linux/x86.csv rename to src/cemu/syscalls/linux/x86.csv diff --git a/cemu/templates/about.html b/src/cemu/templates/about.html similarity index 100% rename from cemu/templates/about.html rename to src/cemu/templates/about.html diff --git a/cemu/templates/cemu.ini b/src/cemu/templates/cemu.ini similarity index 100% rename from cemu/templates/cemu.ini rename to src/cemu/templates/cemu.ini diff --git a/cemu/templates/linux/template.asm b/src/cemu/templates/linux/template.asm similarity index 100% rename from cemu/templates/linux/template.asm rename to src/cemu/templates/linux/template.asm diff --git a/cemu/templates/linux/template.c b/src/cemu/templates/linux/template.c similarity index 100% rename from cemu/templates/linux/template.c rename to src/cemu/templates/linux/template.c diff --git a/cemu/ui/__init__.py b/src/cemu/ui/__init__.py similarity index 100% rename from cemu/ui/__init__.py rename to src/cemu/ui/__init__.py diff --git a/cemu/ui/codeeditor.py b/src/cemu/ui/codeeditor.py similarity index 94% rename from cemu/ui/codeeditor.py rename to src/cemu/ui/codeeditor.py index 001f95b..8ce7904 100644 --- a/cemu/ui/codeeditor.py +++ b/src/cemu/ui/codeeditor.py @@ -22,7 +22,7 @@ DEFAULT_ASSEMBLY_VIEW_FONT, DEFAULT_ASSEMBLY_VIEW_FONT_SIZE, DEFAULT_CODE_VIEW_FONT, - DEFAULT_CODE_VIEW_FONT_SIZE + DEFAULT_CODE_VIEW_FONT_SIZE, ) from cemu.log import error @@ -38,9 +38,7 @@ class CodeEdit(QTextEdit): def __init__(self, parent: Optional[QWidget] = None): super(CodeEdit, self).__init__(parent) self.cursorPositionChanged.connect(self.UpdateHighlightedLine) - self.setFont( - QFont(DEFAULT_CODE_VIEW_FONT, pointSize=DEFAULT_CODE_VIEW_FONT_SIZE) - ) + self.setFont(QFont(DEFAULT_CODE_VIEW_FONT, pointSize=DEFAULT_CODE_VIEW_FONT_SIZE)) self.setFrameStyle(QFrame.Shape.Panel | QFrame.Shape.NoFrame) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) @@ -73,7 +71,7 @@ def update_assembly_code_pane(self): # text: str = self.editor.toPlainText() cur: int = self.editor.textCursor().position() - if cur < 1 or text[cur - 1] != '\n': + if cur < 1 or text[cur - 1] != "\n": return # @@ -82,8 +80,8 @@ def update_assembly_code_pane(self): pane_width = self.width() // 10 lines: list[str] = text.splitlines() bytecode_lines: list[str] = [ - "", - ] * pane_width + "", + ] * pane_width assembly_failed_lines: list[int] = [] for i in range(len(lines)): @@ -106,9 +104,7 @@ def update_assembly_code_pane(self): bytecode_lines[i] = "" if assembly_failed_lines: - msg = ( - f"Failed to assemble lines {', '.join(map(str, assembly_failed_lines))}" - ) + msg = f"Failed to assemble lines {', '.join(map(str, assembly_failed_lines))}" if msg != self.__last_assembly_error_msg: error(msg) self.__last_assembly_error_msg = msg diff --git a/cemu/ui/command.py b/src/cemu/ui/command.py similarity index 91% rename from cemu/ui/command.py rename to src/cemu/ui/command.py index ea2c73c..8df42e4 100644 --- a/cemu/ui/command.py +++ b/src/cemu/ui/command.py @@ -60,18 +60,10 @@ def __init__(self, parent: CEmuWindow, *args, **kwargs): # self.emulator: Emulator = cemu.core.context.emulator - self.emulator.add_state_change_cb( - EmulatorState.NOT_RUNNING, self.onNotRunningUpdateCommandButtons - ) - self.emulator.add_state_change_cb( - EmulatorState.RUNNING, self.onRunningUpdateCommandButtons - ) - self.emulator.add_state_change_cb( - EmulatorState.IDLE, self.onIdleUpdateCommandButtons - ) - self.emulator.add_state_change_cb( - EmulatorState.FINISHED, self.onFinishedUpdateCommandButtons - ) + self.emulator.add_state_change_cb(EmulatorState.NOT_RUNNING, self.onNotRunningUpdateCommandButtons) + self.emulator.add_state_change_cb(EmulatorState.RUNNING, self.onRunningUpdateCommandButtons) + self.emulator.add_state_change_cb(EmulatorState.IDLE, self.onIdleUpdateCommandButtons) + self.emulator.add_state_change_cb(EmulatorState.FINISHED, self.onFinishedUpdateCommandButtons) def onClickRunAll(self) -> None: """ diff --git a/cemu/ui/highlighter.py b/src/cemu/ui/highlighter.py similarity index 100% rename from cemu/ui/highlighter.py rename to src/cemu/ui/highlighter.py diff --git a/cemu/ui/log.py b/src/cemu/ui/log.py similarity index 100% rename from cemu/ui/log.py rename to src/cemu/ui/log.py diff --git a/cemu/ui/main.py b/src/cemu/ui/main.py similarity index 91% rename from cemu/ui/main.py rename to src/cemu/ui/main.py index 507d7c3..9566a80 100644 --- a/cemu/ui/main.py +++ b/src/cemu/ui/main.py @@ -64,9 +64,7 @@ def __init__(self, app: QApplication, *args, **kwargs): # self.signals = {} Unused? self.current_file: Optional[pathlib.Path] = None self.__background_emulator_thread: EmulationRunner = EmulationRunner() - cemu.core.context.emulator.set_threaded_runner( - self.__background_emulator_thread - ) + cemu.core.context.emulator.set_threaded_runner(self.__background_emulator_thread) self.shortcuts: ShortcutManager = ShortcutManager() @@ -103,14 +101,10 @@ def __init__(self, app: QApplication, *args, **kwargs): # register the callbacks for the emulator emu = cemu.core.context.emulator - emu.add_state_change_cb( - EmulatorState.NOT_RUNNING, self.update_layout_not_running - ) + emu.add_state_change_cb(EmulatorState.NOT_RUNNING, self.update_layout_not_running) emu.add_state_change_cb(EmulatorState.RUNNING, self.update_layout_running) emu.add_state_change_cb(EmulatorState.IDLE, self.update_layout_step_running) - emu.add_state_change_cb( - EmulatorState.FINISHED, self.update_layout_step_finished - ) + emu.add_state_change_cb(EmulatorState.FINISHED, self.update_layout_step_finished) # show everything start_in_full_screen = cemu.core.context.settings.getboolean("Global", "StartInFullScreen") @@ -309,9 +303,7 @@ def setMainWindowMenuBar(self): action.triggered.connect(self.openRecentFile) self.recentFileActions.append(action) - clearRecentFilesAction = self.addMenuItem( - "Clear Recent Files", self.clearRecentFiles, "Clear Recent Files", "" - ) + clearRecentFilesAction = self.addMenuItem("Clear Recent Files", self.clearRecentFiles, "Clear Recent Files", "") openRecentFilesSubMenu.addActions(self.recentFileActions) openRecentFilesSubMenu.addSeparator() @@ -344,12 +336,8 @@ def setMainWindowMenuBar(self): self.archActions[label].setEnabled(False) self.currentAction = self.archActions[label] - self.archActions[label].setStatusTip( - f"Change the architecture to '{label}'" - ) - self.archActions[label].triggered.connect( - functools.partial(self.onUpdateArchitecture, arch) - ) + self.archActions[label].setStatusTip(f"Change the architecture to '{label}'") + self.archActions[label].triggered.connect(functools.partial(self.onUpdateArchitecture, arch)) archSubMenu.addAction(self.archActions[label]) # Add the View Window menu bar @@ -386,9 +374,7 @@ def setMainWindowMenuBar(self): self.shortcuts.shortcut("shortcut_popup"), ) - aboutAction = self.addMenuItem( - "About", self.about_popup, self.shortcuts.description("about_popup") - ) + aboutAction = self.addMenuItem("About", self.about_popup, self.shortcuts.description("about_popup")) helpMenu.addAction(shortcutAction) helpMenu.addAction(aboutAction) @@ -479,9 +465,7 @@ def openRecentFile(self): return def loadCode(self, title, filter, run_disassembler): - qFile, _ = QFileDialog.getOpenFileName( - self, title, str(EXAMPLE_PATH), filter + ";;All files (*.*)" - ) + qFile, _ = QFileDialog.getOpenFileName(self, title, str(EXAMPLE_PATH), filter + ";;All files (*.*)") fpath = pathlib.Path(qFile).resolve().absolute() if not fpath.is_file(): @@ -491,14 +475,7 @@ def loadCode(self, title, filter, run_disassembler): if run_disassembler: with tempfile.NamedTemporaryFile("w", suffix=".asm", delete=False) as fd: disassembled_instructions = cemu.utils.disassemble_file(fpath) - fd.write( - os.linesep.join( - [ - f"{insn.mnemonic}, {insn.operands}" - for insn in disassembled_instructions - ] - ) - ) + fd.write(os.linesep.join([f"{insn.mnemonic}, {insn.operands}" for insn in disassembled_instructions])) fpath = pathlib.Path(fd.name) self.loadFile(fpath) @@ -519,9 +496,7 @@ def loadDumpFile(self): def saveCode(self, title, filter, run_assembler): dbg(f"Saving content of '{title}'") - qFile, _ = QFileDialog().getSaveFileName( - self, title, str(HOME), filter=filter + ";;All files (*.*)" - ) + qFile, _ = QFileDialog().getSaveFileName(self, title, str(HOME), filter=filter + ";;All files (*.*)") if not qFile: return @@ -544,9 +519,7 @@ def saveCode(self, title, filter, run_assembler): def pick_file(self, title: str, file_picker_filter: str) -> Optional[pathlib.Path]: dbg(f"Saving content of '{title}'") - qFile, _ = QFileDialog().getSaveFileName( - self, title, str(HOME), filter=file_picker_filter + ";;All files (*.*)" - ) + qFile, _ = QFileDialog().getSaveFileName(self, title, str(HOME), filter=file_picker_filter + ";;All files (*.*)") if not qFile: return None @@ -558,14 +531,10 @@ def pick_file(self, title: str, file_picker_filter: str) -> Optional[pathlib.Pat return fpath def saveCodeText(self): - return self.saveCode( - "Save Assembly Pane As", "Assembly files (*.asm *.s)", False - ) + return self.saveCode("Save Assembly Pane As", "Assembly files (*.asm *.s)", False) def saveCodeBin(self): - return self.saveCode( - "Save Raw Binary Pane As", "Raw binary files (*.raw)", True - ) + return self.saveCode("Save Raw Binary Pane As", "Raw binary files (*.raw)", True) def saveAsCFile(self): template = (TEMPLATE_PATH / "linux" / "template.c").open("r").read() @@ -614,9 +583,7 @@ def generate_pe(self) -> None: insns = cemu.utils.assemble(code) if len(insns) > 0: asm_code = b"".join([x.bytes for x in insns]) - pe = cemu.exports.build_pe_executable( - asm_code, memory_layout, cemu.core.context.architecture - ) + pe = cemu.exports.build_pe_executable(asm_code, memory_layout, cemu.core.context.architecture) info(f"PE file written as '{pe}'") except Exception as e: error(f"PE creation triggered an exception: {e}") @@ -630,17 +597,13 @@ def generate_elf(self) -> None: insns = cemu.utils.assemble(code) if len(insns) > 0: asm_code = b"".join([x.bytes for x in insns]) - elf = cemu.exports.build_pe_executable( - asm_code, memory_layout, cemu.core.context.architecture - ) + elf = cemu.exports.build_pe_executable(asm_code, memory_layout, cemu.core.context.architecture) info(f"ELF file written as '{elf}'") except Exception as e: error(f"ELF creation triggered an exception: {str(e)}") return - def onUpdateArchitecture( - self, arch: Architecture, endian: Optional[Endianness] = None - ) -> None: + def onUpdateArchitecture(self, arch: Architecture, endian: Optional[Endianness] = None) -> None: """Callback triggered when there's a change of Architecture in the UI Args: @@ -694,9 +657,7 @@ def showShortcutPopup(self): def about_popup(self): templ = (TEMPLATE_PATH / "about.html").open().read() - desc = templ.format( - author=AUTHOR, version=VERSION, project_link=URL, issues_link=ISSUE_LINK - ) + desc = templ.format(author=AUTHOR, version=VERSION, project_link=URL, issues_link=ISSUE_LINK) msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Icon.Information) msgbox.setWindowTitle("About CEMU") diff --git a/cemu/ui/mapping.py b/src/cemu/ui/mapping.py similarity index 87% rename from cemu/ui/mapping.py rename to src/cemu/ui/mapping.py index af18720..2057cf1 100644 --- a/cemu/ui/mapping.py +++ b/src/cemu/ui/mapping.py @@ -17,7 +17,7 @@ import cemu.core from cemu.emulator import Emulator, EmulatorState -from cemu.log import error, info +from cemu.log import error from cemu.memory import MemorySection from cemu.utils import format_address @@ -40,12 +40,8 @@ def __init__(self, parent: "CEmuWindow"): self.MemoryMapTableWidget.setColumnWidth(1, 120) self.MemoryMapTableWidget.setColumnWidth(2, 120) self.MemoryMapTableWidget.setColumnWidth(3, 120) - self.MemoryMapTableWidget.setSelectionBehavior( - QTableWidget.SelectionBehavior.SelectRows - ) - self.MemoryMapTableWidget.setHorizontalHeaderLabels( - ["Start", "End", "Name", "Permission"] - ) + self.MemoryMapTableWidget.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows) + self.MemoryMapTableWidget.setHorizontalHeaderLabels(["Start", "End", "Name", "Permission"]) self.MemoryMapTableWidget.verticalHeader().setVisible(False) layout.addWidget(self.MemoryMapTableWidget) @@ -69,16 +65,10 @@ def __init__(self, parent: "CEmuWindow"): # Emulator state callback # self.emu: Emulator = cemu.core.context.emulator - self.emu.add_state_change_cb( - EmulatorState.NOT_RUNNING, self.onNotRunningUpdateMemoryMap - ) - self.emu.add_state_change_cb( - EmulatorState.RUNNING, self.onRunningDisableMemoryMapGrid - ) + self.emu.add_state_change_cb(EmulatorState.NOT_RUNNING, self.onNotRunningUpdateMemoryMap) + self.emu.add_state_change_cb(EmulatorState.RUNNING, self.onRunningDisableMemoryMapGrid) self.emu.add_state_change_cb(EmulatorState.IDLE, self.onIdleEnableMemoryMapGrid) - self.emu.add_state_change_cb( - EmulatorState.FINISHED, self.onFinishedEnableMemoryMapGrid - ) + self.emu.add_state_change_cb(EmulatorState.FINISHED, self.onFinishedEnableMemoryMapGrid) def onNotRunningUpdateMemoryMap(self) -> None: self.redraw_memory_map_table() @@ -99,9 +89,7 @@ def redraw_memory_map_table(self) -> None: self.MemoryMapTableWidget.insertRow(idx) name = QTableWidgetItem(section.name) start_address = QTableWidgetItem(format_address(section.address)) - end_address = QTableWidgetItem( - format_address(section.address + section.size) - ) + end_address = QTableWidgetItem(format_address(section.address + section.size)) permission = QTableWidgetItem(str(section.permission)) self.MemoryMapTableWidget.setItem(idx, 0, start_address) self.MemoryMapTableWidget.setItem(idx, 1, end_address) @@ -185,9 +173,7 @@ def add_or_edit_section_popup(self) -> None: wid.setMinimumWidth(400) layout.addWidget(wid) - msgbox.setStandardButtons( - QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel - ) + msgbox.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel) ret = msgbox.exec() if ret == QMessageBox.StandardButton.Ok: @@ -199,10 +185,7 @@ def add_or_edit_section_popup(self) -> None: error("section name already exists") return - memory_set = ( - set(range(x.address, x.address + x.size)) - for x in cemu.core.context.emulator.sections - ) + memory_set = (set(range(x.address, x.address + x.size)) for x in cemu.core.context.emulator.sections) current_set = set(range(address, address + size)) for m in memory_set: if len(current_set & m) != 0: diff --git a/cemu/ui/memory.py b/src/cemu/ui/memory.py similarity index 94% rename from cemu/ui/memory.py rename to src/cemu/ui/memory.py index 11cbaa6..4985f9d 100644 --- a/cemu/ui/memory.py +++ b/src/cemu/ui/memory.py @@ -47,9 +47,7 @@ def __init__(self, parent: CEmuWindow, *args, **kwargs): memview_layout = QVBoxLayout() self.editor = QTextEdit() self.editor.setFrameStyle(QFrame.Shape.Panel | QFrame.Shape.NoFrame) - self.editor.setFont( - QFont(const.DEFAULT_MEMORY_VIEW_FONT, const.DEFAULT_MEMORY_VIEW_FONT_SIZE) - ) + self.editor.setFont(QFont(const.DEFAULT_MEMORY_VIEW_FONT, const.DEFAULT_MEMORY_VIEW_FONT_SIZE)) self.editor.setReadOnly(True) memview_layout.addWidget(title_widget) memview_layout.addWidget(self.editor) @@ -63,9 +61,7 @@ def __init__(self, parent: CEmuWindow, *args, **kwargs): # emu: Emulator = cemu.core.context.emulator emu.add_state_change_cb(EmulatorState.IDLE, self.onIdleRefreshMemoryEditor) - emu.add_state_change_cb( - EmulatorState.FINISHED, self.onFinishedClearMemoryEditor - ) + emu.add_state_change_cb(EmulatorState.FINISHED, self.onFinishedClearMemoryEditor) return diff --git a/cemu/ui/registers.py b/src/cemu/ui/registers.py similarity index 90% rename from cemu/ui/registers.py rename to src/cemu/ui/registers.py index 0f159e6..a95765f 100644 --- a/cemu/ui/registers.py +++ b/src/cemu/ui/registers.py @@ -47,9 +47,7 @@ def __init__(self, parent, *args, **kwargs): # emu: Emulator = cemu.core.context.emulator emu.add_state_change_cb(EmulatorState.IDLE, self.onIdleRefreshRegisterGrid) - emu.add_state_change_cb( - EmulatorState.FINISHED, self.onFinishedRefreshRegisterGrid - ) + emu.add_state_change_cb(EmulatorState.FINISHED, self.onFinishedRefreshRegisterGrid) emu.add_state_change_cb(EmulatorState.NOT_RUNNING, self.updateGrid) return @@ -87,14 +85,8 @@ def updateGrid(self) -> None: ) if old_val != val: self.__old_register_values[reg] = val - value.setForeground( - QColor(DEFAULT_REGISTER_VIEW_CHANGED_REGISTER_COLOR) - ) - value.setFlags( - Qt.ItemFlag.ItemIsEnabled - | Qt.ItemFlag.ItemIsSelectable - | Qt.ItemFlag.ItemIsEditable - ) + value.setForeground(QColor(DEFAULT_REGISTER_VIEW_CHANGED_REGISTER_COLOR)) + value.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable) self.RegisterTableWidget.setItem(i, 0, name) self.RegisterTableWidget.setItem(i, 1, value) diff --git a/cemu/ui/utils.py b/src/cemu/ui/utils.py similarity index 93% rename from cemu/ui/utils.py rename to src/cemu/ui/utils.py index a3bd173..03a5dc5 100644 --- a/cemu/ui/utils.py +++ b/src/cemu/ui/utils.py @@ -75,7 +75,7 @@ def is_dark_mode(palette: QPalette) -> bool: def brighten_color(hex_color: str, percent: float) -> str: # Remove the '#' if it exists - hex_color = hex_color.lstrip('#') + hex_color = hex_color.lstrip("#") # Convert hex to RGB r = int(hex_color[0:2], 16) @@ -88,12 +88,12 @@ def brighten_color(hex_color: str, percent: float) -> str: b = min(255, int(b * (1 + percent / 100))) # Convert RGB back to hex - return f'{r:02x}{g:02x}{b:02x}' + return f"{r:02x}{g:02x}{b:02x}" def hex_to_rgb(hex_color: str) -> tuple[int, ...]: - hex_color = hex_color.lstrip('#') - return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4)) + hex_color = hex_color.lstrip("#") + return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4)) def is_red(hex_color: str) -> bool: diff --git a/cemu/utils.py b/src/cemu/utils.py similarity index 96% rename from cemu/utils.py rename to src/cemu/utils.py index 21b4c6c..7c00477 100644 --- a/cemu/utils.py +++ b/src/cemu/utils.py @@ -94,9 +94,7 @@ def __str__(self): return f'Instruction({self.address:#x}, "{self.mnemonic} {self.operands}")' -def disassemble( - raw_data: bytes, count: int = -1, base: int = DISASSEMBLY_DEFAULT_BASE_ADDRESS -) -> list[Instruction]: +def disassemble(raw_data: bytes, count: int = -1, base: int = DISASSEMBLY_DEFAULT_BASE_ADDRESS) -> list[Instruction]: """Disassemble the code given as raw data, with the given architecture. Args: @@ -125,9 +123,7 @@ def disassemble_file(fpath: pathlib.Path) -> list[Instruction]: return disassemble(f.read()) -def assemble( - code: str, base_address: int = DISASSEMBLY_DEFAULT_BASE_ADDRESS -) -> list[Instruction]: +def assemble(code: str, base_address: int = DISASSEMBLY_DEFAULT_BASE_ADDRESS) -> list[Instruction]: """ Helper function to assemble code receive in parameter `asm_code` using Keystone. diff --git a/tests/test_basic.py b/tests/test_basic.py index 189e768..0e541d7 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -91,9 +91,8 @@ def run(self): last_insn_address = self.emu.start_addr + len(self.emu.code) if self.emu.use_step_mode: - insn = self.emu.next_instruction( - self.emu.code[start_offset:], start_address + start_offset - ) + insn = self.emu.next_instruction(self.emu.code[start_offset:], start_address + start_offset) + assert insn end_address = insn.end else: end_address = last_insn_address @@ -202,9 +201,7 @@ def test_matrix_execute_assembly_regs(self): or isinstance(tc.arch, cemu.arch.arm.ARM) or isinstance(tc.arch, cemu.arch.arm.AARCH64) ): - assert self.emu.pc() == self.emu.sections[0].address + len( - self.emu.code - ) + assert self.emu.pc() == self.emu.sections[0].address + len(self.emu.code) assert self.emu.state == EmulatorState.FINISHED assert tc.result() diff --git a/tests/test_memory.py b/tests/test_memory.py index 364ffd5..2dddf35 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -9,10 +9,7 @@ def test_memory_conversion_from_string(self): assert MemoryPermission.from_string("Read") == MemoryPermission.READ assert MemoryPermission.from_string("wRIte") == MemoryPermission.WRITE assert MemoryPermission.from_string("exeC") == MemoryPermission.EXECUTE - assert ( - MemoryPermission.from_string("Read|wRIte|wRIte") - == MemoryPermission.READ | MemoryPermission.WRITE - ) + assert MemoryPermission.from_string("Read|wRIte|wRIte") == MemoryPermission.READ | MemoryPermission.WRITE assert MemoryPermission.from_string("Read|wRIte|exec") == MemoryPermission.ALL with pytest.raises(ValueError) as _: @@ -21,25 +18,12 @@ def test_memory_conversion_from_string(self): def test_memory_conversion_from_windows(self): assert MemoryPermission.from_windows(0x01) == MemoryPermission.NONE assert MemoryPermission.from_windows(0x02) == MemoryPermission.READ - assert ( - MemoryPermission.from_windows(0x04) - == MemoryPermission.READ | MemoryPermission.WRITE - ) - assert ( - MemoryPermission.from_windows(0x08) - == MemoryPermission.READ | MemoryPermission.WRITE - ) + assert MemoryPermission.from_windows(0x04) == MemoryPermission.READ | MemoryPermission.WRITE + assert MemoryPermission.from_windows(0x08) == MemoryPermission.READ | MemoryPermission.WRITE assert MemoryPermission.from_windows(0x10) == MemoryPermission.EXECUTE - assert ( - MemoryPermission.from_windows(0x20) - == MemoryPermission.EXECUTE | MemoryPermission.READ - ) - assert MemoryPermission.from_windows(0x40) == ( - MemoryPermission.READ | MemoryPermission.WRITE | MemoryPermission.EXECUTE - ) - assert MemoryPermission.from_windows(0x80) == ( - MemoryPermission.READ | MemoryPermission.WRITE | MemoryPermission.EXECUTE - ) + assert MemoryPermission.from_windows(0x20) == MemoryPermission.EXECUTE | MemoryPermission.READ + assert MemoryPermission.from_windows(0x40) == (MemoryPermission.READ | MemoryPermission.WRITE | MemoryPermission.EXECUTE) + assert MemoryPermission.from_windows(0x80) == (MemoryPermission.READ | MemoryPermission.WRITE | MemoryPermission.EXECUTE) with pytest.raises(NotImplementedError) as _: MemoryPermission.from_windows(0x100) From 7465ab36bafe0e605d76bd66f3ee8e8d78a8f432 Mon Sep 17 00:00:00 2001 From: hugsy Date: Tue, 30 Jul 2024 12:42:42 -0700 Subject: [PATCH 2/3] [ci] use rye too --- .github/workflows/build.yml | 118 +++++++++++++++++++--------------- .github/workflows/notify.yml | 7 +- .github/workflows/publish.yml | 26 +++++--- 3 files changed, 87 insertions(+), 64 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f4ce39..4ac686d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,8 +12,7 @@ on: env: NAME: cemu REPO: hugsy/cemu - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - VERSION: 0.8 + VERSION: 0.8.0 jobs: build: @@ -42,56 +41,67 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: "Install Pre-requisite (Linux)" - if: matrix.os == 'ubuntu-latest' - shell: bash - run: | - sudo apt update - sudo apt upgrade -y - sudo apt install -y build-essential libegl1 libgl1-mesa-glx python3-dev python3-pip python3-wheel python3-setuptools - - - name: "Install Pre-requisite (macOS)" - if: matrix.os == 'macos-latest' - run: | - env - - - name: "Install Pre-requisite (Windows)" - if: matrix.os == 'windows-latest' - shell: pwsh - run: | - env - - - name: Build artifact - shell: bash - run: | - mkdir build - mkdir build/bin - python --version - python -m pip --version - python -m pip install --upgrade pip setuptools wheel - python -m pip install --user --upgrade .[all] - - - name: "Post build Cemu (Windows)" - if: matrix.os == 'windows-latest' - shell: pwsh - run: | - Copy-Item $env:APPDATA\Python\Python*\Scripts\cemu.exe build\bin\ - - - name: "Post build Cemu (Linux)" - if: matrix.os == 'ubuntu-latest' - shell: bash - run: | - cp -v ~/.local/bin/cemu build/bin/ - - - name: "Post build Cemu (macOS)" - if: matrix.os == 'macos-latest' - shell: bash - run: | - cp -v ~/.local/bin/cemu build/bin/ || cp -v /Users/runner/Library/Python/${{ matrix.python-version }}/bin/cemu build/bin/ - - - name: "Run tests" - run: | - python -m pytest tests/ + - name: "Install Pre-requisite" + uses: eifinger/setup-rye@v4 + with: + version: 'latest' + + # - name: "Install Pre-requisite (Linux)" + # if: matrix.os == 'ubuntu-latest' + # shell: bash + # run: | + # sudo apt update + # sudo apt upgrade -y + # sudo apt install -y build-essential libegl1 libgl1-mesa-glx python3-dev python3-pip python3-wheel python3-setuptools + + # - name: "Install Pre-requisite (macOS)" + # if: matrix.os == 'macos-latest' + # run: | + # env + + # - name: "Install Pre-requisite (Windows)" + # if: matrix.os == 'windows-latest' + # shell: pwsh + # run: | + # env + + - run: rye fmt + - run: rye lint + - run: rye test + - run: rye build --wheel --out ./build + + + # - name: Build artifact + # shell: bash + # run: | + # mkdir build + # mkdir build/bin + # python --version + # python -m pip --version + # python -m pip install --upgrade pip setuptools wheel + # python -m pip install --user --upgrade .[all] + + # - name: "Post build Cemu (Windows)" + # if: matrix.os == 'windows-latest' + # shell: pwsh + # run: | + # Copy-Item $env:APPDATA\Python\Python*\Scripts\cemu.exe build\bin\ + + # - name: "Post build Cemu (Linux)" + # if: matrix.os == 'ubuntu-latest' + # shell: bash + # run: | + # cp -v ~/.local/bin/cemu build/bin/ + + # - name: "Post build Cemu (macOS)" + # if: matrix.os == 'macos-latest' + # shell: bash + # run: | + # cp -v ~/.local/bin/cemu build/bin/ || cp -v /Users/runner/Library/Python/${{ matrix.python-version }}/bin/cemu build/bin/ + + # - name: "Run tests" + # run: | + # python -m pytest tests/ - name: Publish artifact id: publish_artifact @@ -133,6 +143,8 @@ jobs: echo "${{ matrix.os }}-$pyVersion=❌ ${{ matrix.os }} ${{ matrix.python-version }}" >> $GITHUB_OUTPUT notify: + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} runs-on: 'ubuntu-latest' needs: build steps: @@ -142,7 +154,7 @@ jobs: RUN_URL: "https://github.com/${{ env.REPO }}/actions/runs/${{ github.run_id }}" BRANCH_URL: "https://github.com/${{ env.REPO }}/tree/${{ github.ref_name }}" AUTHOR_URL: "https://github.com/${{ github.actor }}" - uses: sarisia/actions-status-discord@v1.14.0 + uses: sarisia/actions-status-discord@v1.14.5 with: nodetail: true title: 🚧 🚧 Summary of Build `${{ github.sha }}` for `${{ env.REPO }}` 🚧 🚧 diff --git a/.github/workflows/notify.yml b/.github/workflows/notify.yml index e764da6..02d9839 100644 --- a/.github/workflows/notify.yml +++ b/.github/workflows/notify.yml @@ -1,13 +1,14 @@ name: "Discord Notification" on: [pull_request, issues] -env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + jobs: notify: + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 024670c..d58fac2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,6 +3,9 @@ name: Publish CEmu to PyPI on: workflow_dispatch: push: + branches: + - main + jobs: publish: @@ -15,24 +18,31 @@ jobs: id-token: write steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup uses: actions/setup-python@v4 with: python-version: "3.10" - - name: Requirements - run: | - python -m pip install --upgrade build wheel + - name: "Install Pre-requisite" + uses: eifinger/setup-rye@v4 + with: + version: 'latest' + + - run: rye build --wheel --out ./publish - - name: Build - run: | - python -m build + # - name: Requirements + # run: | + # python -m pip install --upgrade build wheel + + # - name: Build + # run: | + # python -m build - name: Publish uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_API_TOKEN }} print-hash: true - + packages-dir: publish/ From 25f6f86edbefeff2b6a0166e5dcc23903040324a Mon Sep 17 00:00:00 2001 From: crazy hugsy Date: Tue, 30 Jul 2024 12:53:24 -0700 Subject: [PATCH 3/3] [ci] hardcode runners --- .github/workflows/build.yml | 72 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ac686d..2b66235 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,20 +19,20 @@ jobs: strategy: fail-fast: false matrix: - os: [windows-latest, ubuntu-latest, macos-latest] + os: [windows-2019, ubuntu-22.04, macos-13] python-version: ['3.10', '3.11', '3.12'] name: ${{ matrix.os }} / ${{ matrix.python-version }} runs-on: ${{ matrix.os }} outputs: - windows-latest-3-10: ${{ join(steps.*.outputs.windows-latest-3-10,'') }} - windows-latest-3-11: ${{ join(steps.*.outputs.windows-latest-3-11,'') }} - windows-latest-3-12: ${{ join(steps.*.outputs.windows-latest-3-12,'') }} - ubuntu-latest-3-10: ${{ join(steps.*.outputs.ubuntu-latest-3-10,'') }} - ubuntu-latest-3-11: ${{ join(steps.*.outputs.ubuntu-latest-3-11,'') }} - ubuntu-latest-3-12: ${{ join(steps.*.outputs.ubuntu-latest-3-12,'') }} - macos-latest-3-10: ${{ join(steps.*.outputs.macos-latest-3-10,'') }} - macos-latest-3-11: ${{ join(steps.*.outputs.macos-latest-3-11,'') }} - macos-latest-3-12: ${{ join(steps.*.outputs.macos-latest-3-12,'') }} + windows-2019-3-10: ${{ join(steps.*.outputs.windows-2019-3-10,'') }} + windows-2019-3-11: ${{ join(steps.*.outputs.windows-2019-3-11,'') }} + windows-2019-3-12: ${{ join(steps.*.outputs.windows-2019-3-12,'') }} + ubuntu-22.04-3-10: ${{ join(steps.*.outputs.ubuntu-22.04-3-10,'') }} + ubuntu-22.04-3-11: ${{ join(steps.*.outputs.ubuntu-22.04-3-11,'') }} + ubuntu-22.04-3-12: ${{ join(steps.*.outputs.ubuntu-22.04-3-12,'') }} + macos-13-3-10: ${{ join(steps.*.outputs.macos-13-3-10,'') }} + macos-13-3-11: ${{ join(steps.*.outputs.macos-13-3-11,'') }} + macos-13-3-12: ${{ join(steps.*.outputs.macos-13-3-12,'') }} steps: - uses: actions/checkout@v4 @@ -46,21 +46,21 @@ jobs: with: version: 'latest' - # - name: "Install Pre-requisite (Linux)" - # if: matrix.os == 'ubuntu-latest' - # shell: bash - # run: | - # sudo apt update - # sudo apt upgrade -y - # sudo apt install -y build-essential libegl1 libgl1-mesa-glx python3-dev python3-pip python3-wheel python3-setuptools + - name: "Install Pre-requisite (Linux)" + if: matrix.os == 'ubuntu-22.04' + shell: bash + run: | + sudo apt update + sudo apt upgrade -y + sudo apt install -y build-essential libegl1 libgl1-mesa-glx # - name: "Install Pre-requisite (macOS)" - # if: matrix.os == 'macos-latest' + # if: matrix.os == 'macos-13' # run: | # env # - name: "Install Pre-requisite (Windows)" - # if: matrix.os == 'windows-latest' + # if: matrix.os == 'windows-2019' # shell: pwsh # run: | # env @@ -82,19 +82,19 @@ jobs: # python -m pip install --user --upgrade .[all] # - name: "Post build Cemu (Windows)" - # if: matrix.os == 'windows-latest' + # if: matrix.os == 'windows-2019' # shell: pwsh # run: | # Copy-Item $env:APPDATA\Python\Python*\Scripts\cemu.exe build\bin\ # - name: "Post build Cemu (Linux)" - # if: matrix.os == 'ubuntu-latest' + # if: matrix.os == 'ubuntu-22.04' # shell: bash # run: | # cp -v ~/.local/bin/cemu build/bin/ # - name: "Post build Cemu (macOS)" - # if: matrix.os == 'macos-latest' + # if: matrix.os == 'macos-13' # shell: bash # run: | # cp -v ~/.local/bin/cemu build/bin/ || cp -v /Users/runner/Library/Python/${{ matrix.python-version }}/bin/cemu build/bin/ @@ -112,7 +112,7 @@ jobs: - name: Populate the successful output (Windows) id: output_success_windows - if: ${{ matrix.os == 'windows-latest' && success() }} + if: ${{ matrix.os == 'windows-2019' && success() }} shell: pwsh run: | $pyVersion = "${{ matrix.python-version }}" -replace "\.", "-" @@ -120,7 +120,7 @@ jobs: - name: Populate the successful output (Other) id: output_success_other - if: ${{matrix.os != 'windows-latest' && success() }} + if: ${{matrix.os != 'windows-2019' && success() }} shell: bash run: | pyVersion="$(echo -n ${{ matrix.python-version }} | tr . -)" @@ -128,7 +128,7 @@ jobs: - name: Populate the failure output (Windows) id: output_failure_windows - if: ${{matrix.os == 'windows-latest' && failure() }} + if: ${{matrix.os == 'windows-2019' && failure() }} shell: pwsh run: | $pyVersion = "${{ matrix.python-version }}" -replace "\.", "-" @@ -136,7 +136,7 @@ jobs: - name: Populate the failure output (Other) id: output_failure_other - if: ${{matrix.os != 'windows-latest' && failure() }} + if: ${{matrix.os != 'windows-2019' && failure() }} shell: bash run: | pyVersion="$(echo -n ${{ matrix.python-version }} | tr . -)" @@ -145,7 +145,7 @@ jobs: notify: env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - runs-on: 'ubuntu-latest' + runs-on: 'ubuntu-22.04' needs: build steps: - name: Send Discord notification @@ -164,15 +164,15 @@ jobs: ● Branch [`${{ github.ref_name }}`](${{ env.BRANCH_URL }}) ● [Detail Page](${{ env.RUN_URL }}) - ${{ needs.build.outputs.windows-latest-3-10 }} - ${{ needs.build.outputs.windows-latest-3-11 }} - ${{ needs.build.outputs.windows-latest-3-12 }} - ${{ needs.build.outputs.ubuntu-latest-3-10 }} - ${{ needs.build.outputs.ubuntu-latest-3-11 }} - ${{ needs.build.outputs.ubuntu-latest-3-12 }} - ${{ needs.build.outputs.macos-latest-3-10 }} - ${{ needs.build.outputs.macos-latest-3-11 }} - ${{ needs.build.outputs.macos-latest-3-12 }} + ${{ needs.build.outputs.windows-2019-3-10 }} + ${{ needs.build.outputs.windows-2019-3-11 }} + ${{ needs.build.outputs.windows-2019-3-12 }} + ${{ needs.build.outputs.ubuntu-22.04-3-10 }} + ${{ needs.build.outputs.ubuntu-22.04-3-11 }} + ${{ needs.build.outputs.ubuntu-22.04-3-12 }} + ${{ needs.build.outputs.macos-13-3-10 }} + ${{ needs.build.outputs.macos-13-3-11 }} + ${{ needs.build.outputs.macos-13-3-12 }} color: 0x0000ff