Subrepo Updates (#1368)

* git subrepo pull --force tools/asm-processor

subrepo:
  subdir:   "tools/asm-processor"
  merged:   "fed1e3ddb"
upstream:
  origin:   "git@github.com:simonlindholm/asm-processor.git"
  branch:   "main"
  commit:   "fed1e3ddb"
git-subrepo:
  version:  "0.4.6"
  origin:   "git@github.com:ingydotnet/git-subrepo.git"
  commit:   "110b9eb"

* git subrepo pull tools/asm-differ

subrepo:
  subdir:   "tools/asm-differ"
  merged:   "4ed847317"
upstream:
  origin:   "https://github.com/simonlindholm/asm-differ"
  branch:   "main"
  commit:   "4ed847317"
git-subrepo:
  version:  "0.4.6"
  origin:   "git@github.com:ingydotnet/git-subrepo.git"
  commit:   "110b9eb"

* git subrepo pull --force tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "7f398831f"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "7f398831f"
git-subrepo:
  version:  "0.4.6"
  origin:   "git@github.com:ingydotnet/git-subrepo.git"
  commit:   "110b9eb"

* git subrepo pull (merge) --force tools/fado

subrepo:
  subdir:   "tools/fado"
  merged:   "8ce048376"
upstream:
  origin:   "git@github.com:EllipticEllipsis/fado.git"
  branch:   "master"
  commit:   "8ce048376"
git-subrepo:
  version:  "0.4.6"
  origin:   "git@github.com:ingydotnet/git-subrepo.git"
  commit:   "110b9eb"
This commit is contained in:
Derek Hensley 2023-09-08 03:17:54 -07:00 committed by GitHub
parent 4fa13e4132
commit c8304925da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 905 additions and 88 deletions

View File

@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/zeldaret/ZAPD.git remote = https://github.com/zeldaret/ZAPD.git
branch = master branch = master
commit = 505024b33eb1fcd00e3e9bb71f1355fa2ae6e9cf commit = 7f398831fbcf67210b37882b5017093a1d187d5c
parent = 387d3597142ebdbebe1fbb99858ea831aa2752b4 parent = 71e36ae371f89b5f86a6d59c7ebc24b8a55ee43e
method = merge method = merge
cmdver = 0.4.6 cmdver = 0.4.6

View File

@ -8,6 +8,18 @@ COPYCHECK_ARGS ?=
LLD ?= 0 LLD ?= 0
WERROR ?= 0 WERROR ?= 0
# On MacOS 10.14, use boost::filesystem, because
# the system doesn't supply std::filesystem.
ifneq ($(OS),Windows_NT)
ifeq ($(shell uname -s),Darwin)
MACOS_VERSION := $(shell sw_vers -productVersion | cut -d . -f 1,2)
ifeq ($(MACOS_VERSION),10.14)
USE_BOOST_FS ?= 1
endif
endif
endif
USE_BOOST_FS ?= 0
# Use clang++ if available, else use g++ # Use clang++ if available, else use g++
ifeq ($(shell command -v clang++ >/dev/null 2>&1; echo $$?),0) ifeq ($(shell command -v clang++ >/dev/null 2>&1; echo $$?),0)
CXX := clang++ CXX := clang++
@ -46,6 +58,11 @@ endif
LDFLAGS := -lm -ldl -lpng LDFLAGS := -lm -ldl -lpng
ifneq ($(USE_BOOST_FS),0)
CXXFLAGS += -DUSE_BOOST_FS
LDFLAGS += -lboost_filesystem
endif
# Use LLD if available. Set LLD=0 to not use it # Use LLD if available. Set LLD=0 to not use it
ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0) ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0)
LLD := 1 LLD := 1

View File

@ -2,6 +2,7 @@
#include <functional> #include <functional>
#include <string_view> #include <string_view>
#include <unordered_map>
#include "Utils/Directory.h" #include "Utils/Directory.h"
#include "Utils/File.h" #include "Utils/File.h"

View File

@ -4,7 +4,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if __has_include(<filesystem>) #ifdef USE_BOOST_FS
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#elif __has_include(<filesystem>)
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else #else
@ -17,7 +20,11 @@ namespace fs = std::experimental::filesystem;
class Directory class Directory
{ {
public: public:
#ifdef USE_BOOST_FS
static std::string GetCurrentDirectory() { return fs::current_path().string(); }
#else
static std::string GetCurrentDirectory() { return fs::current_path().u8string(); } static std::string GetCurrentDirectory() { return fs::current_path().u8string(); }
#endif
static bool Exists(const fs::path& path) { return fs::exists(path); } static bool Exists(const fs::path& path) { return fs::exists(path); }

View File

@ -1,6 +1,11 @@
#pragma once #pragma once
#ifdef USE_BOOST_FS
#include <boost/filesystem/fstream.hpp>
#else
#include <fstream> #include <fstream>
#endif
#include <string> #include <string>
#include <vector> #include <vector>
#include "Directory.h" #include "Directory.h"
@ -8,16 +13,24 @@
class File class File
{ {
#ifdef USE_BOOST_FS
typedef fs::ifstream ifstream;
typedef fs::ofstream ofstream;
#else
typedef std::ifstream ifstream;
typedef std::ofstream ofstream;
#endif
public: public:
static bool Exists(const fs::path& filePath) static bool Exists(const fs::path& filePath)
{ {
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
return file.good(); return file.good();
} }
static std::vector<uint8_t> ReadAllBytes(const fs::path& filePath) static std::vector<uint8_t> ReadAllBytes(const fs::path& filePath)
{ {
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
int32_t fileSize = (int32_t)file.tellg(); int32_t fileSize = (int32_t)file.tellg();
file.seekg(0); file.seekg(0);
char* data = new char[fileSize]; char* data = new char[fileSize];
@ -31,7 +44,7 @@ public:
static std::string ReadAllText(const fs::path& filePath) static std::string ReadAllText(const fs::path& filePath)
{ {
std::ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate); ifstream file(filePath, std::ios::in | std::ios::binary | std::ios::ate);
if (!file.is_open()) if (!file.is_open())
return ""; return "";
int32_t fileSize = (int32_t)file.tellg(); int32_t fileSize = (int32_t)file.tellg();
@ -56,28 +69,28 @@ public:
static void WriteAllBytes(const fs::path& filePath, const std::vector<uint8_t>& data) static void WriteAllBytes(const fs::path& filePath, const std::vector<uint8_t>& data)
{ {
std::ofstream file(filePath, std::ios::binary); ofstream file(filePath, std::ios::binary);
file.write((char*)data.data(), data.size()); file.write((char*)data.data(), data.size());
file.close(); file.close();
}; };
static void WriteAllBytes(const std::string& filePath, const std::vector<char>& data) static void WriteAllBytes(const std::string& filePath, const std::vector<char>& data)
{ {
std::ofstream file(filePath, std::ios::binary); ofstream file(filePath, std::ios::binary);
file.write((char*)data.data(), data.size()); file.write((char*)data.data(), data.size());
file.close(); file.close();
}; };
static void WriteAllBytes(const std::string& filePath, const char* data, int dataSize) static void WriteAllBytes(const std::string& filePath, const char* data, int dataSize)
{ {
std::ofstream file(filePath, std::ios::binary); ofstream file(filePath, std::ios::binary);
file.write((char*)data, dataSize); file.write((char*)data, dataSize);
file.close(); file.close();
}; };
static void WriteAllText(const fs::path& filePath, const std::string& text) static void WriteAllText(const fs::path& filePath, const std::string& text)
{ {
std::ofstream file(filePath, std::ios::out); ofstream file(filePath, std::ios::out);
file.write(text.c_str(), text.size()); file.write(text.c_str(), text.size());
file.close(); file.close();
} }

View File

@ -4,7 +4,10 @@
#include <string> #include <string>
#include "Utils/StringHelper.h" #include "Utils/StringHelper.h"
#if __has_include(<filesystem>) #ifdef USE_BOOST_FS
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#elif __has_include(<filesystem>)
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem; namespace fs = std::filesystem;
#else #else

View File

@ -0,0 +1,20 @@
name: flake check
on:
pull_request:
push:
permissions: read-all
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Install `nix` which is just a dead-simple way to get a stable `poetry`
# in scope.
- uses: cachix/install-nix-action@v20
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
# Check that poetry.lock is in sync with pyproject.toml
- run: nix run github:NixOS/nixpkgs/22.11#poetry -- lock --check

View File

@ -0,0 +1,15 @@
name: unit tests
on:
pull_request:
push:
permissions: read-all
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: python3 -m pip install --user colorama watchdog levenshtein cxxfilt
- run: python3 test.py

View File

@ -1,4 +1,3 @@
.mypy_cache/ .mypy_cache/
__pycache__/ __pycache__/
.vscode/ .vscode/
poetry.lock

View File

@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = https://github.com/simonlindholm/asm-differ remote = https://github.com/simonlindholm/asm-differ
branch = main branch = main
commit = ae408664a89ea4dc70d005d0afc69ac26c938cbb commit = 4ed8473173c5a4d6d62337ee4759fdbd93fcf20b
parent = c833969ea79ba31c3103e25e94ef88098c0287de parent = 862e62040f70cb24d66e893ff4299b79fda9407d
method = merge method = merge
cmdver = 0.4.3 cmdver = 0.4.6

View File

@ -1,6 +1,6 @@
# asm-differ # asm-differ
Nice differ for assembly code. Currently supports MIPS, PPC, AArch64, and ARM32; should be easy to hack to support other instruction sets. Nice differ for assembly code. Currently supports MIPS, PPC, AArch64, ARM32, SH2, SH4, and m68k; should be easy to hack to support other instruction sets.
![](screenshot.png) ![](screenshot.png)

View File

@ -54,7 +54,7 @@ if __name__ == "__main__":
argcomplete = None argcomplete = None
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Diff MIPS, PPC, AArch64, or ARM32 assembly." description="Diff MIPS, PPC, AArch64, ARM32, SH2, SH4, or m68k assembly."
) )
start_argument = parser.add_argument( start_argument = parser.add_argument(
@ -120,11 +120,11 @@ if __name__ == "__main__":
) )
parser.add_argument( parser.add_argument(
"-f", "-f",
"--objfile", "--file",
dest="objfile", dest="file",
type=str, type=str,
help="""File path for an object file being diffed. When used help="""File path for a file being diffed. When used the map
the map file isn't searched for the function given. Useful for dynamically file isn't searched for the function given. Useful for dynamically
linked libraries.""", linked libraries.""",
) )
parser.add_argument( parser.add_argument(
@ -212,9 +212,9 @@ if __name__ == "__main__":
"-s", "-s",
"--stop-at-ret", "--stop-at-ret",
dest="stop_at_ret", dest="stop_at_ret",
action="store_true", action="count",
help="""Stop disassembling at the first return instruction. help="""Stop disassembling at the first return instruction.
Some functions have multiple return points, so use with care!""", You can also pass -ss to stop at the second return instruction, and so on.""",
) )
parser.add_argument( parser.add_argument(
"-i", "-i",
@ -264,6 +264,14 @@ if __name__ == "__main__":
help="""Automatically update when source/object files change. help="""Automatically update when source/object files change.
Recommended in combination with -m.""", Recommended in combination with -m.""",
) )
parser.add_argument(
"-y",
"--yes",
dest="agree",
action="store_true",
help="""Automatically agree to any yes/no questions asked.
Useful if you really want to use the -w option without -m."""
)
parser.add_argument( parser.add_argument(
"-0", "-0",
"--diff_mode=single_base", "--diff_mode=single_base",
@ -407,7 +415,7 @@ class ProjectSettings:
build_command: List[str] build_command: List[str]
map_format: str map_format: str
build_dir: str build_dir: str
ms_map_address_offset: int map_address_offset: int
baseimg: Optional[str] baseimg: Optional[str]
myimg: Optional[str] myimg: Optional[str]
mapfile: Optional[str] mapfile: Optional[str]
@ -431,7 +439,7 @@ class Config:
# Build/objdump options # Build/objdump options
diff_obj: bool diff_obj: bool
objfile: Optional[str] file: Optional[str]
make: bool make: bool
source_old_binutils: bool source_old_binutils: bool
diff_section: str diff_section: str
@ -449,7 +457,7 @@ class Config:
show_branches: bool show_branches: bool
show_line_numbers: bool show_line_numbers: bool
show_source: bool show_source: bool
stop_at_ret: bool stop_at_ret: Optional[int]
ignore_large_imms: bool ignore_large_imms: bool
ignore_addr_diffs: bool ignore_addr_diffs: bool
algorithm: str algorithm: str
@ -481,7 +489,9 @@ def create_project_settings(settings: Dict[str, Any]) -> ProjectSettings:
objdump_flags=settings.get("objdump_flags", []), objdump_flags=settings.get("objdump_flags", []),
expected_dir=settings.get("expected_dir", "expected/"), expected_dir=settings.get("expected_dir", "expected/"),
map_format=settings.get("map_format", "gnu"), map_format=settings.get("map_format", "gnu"),
ms_map_address_offset=settings.get("ms_map_address_offset", 0), map_address_offset=settings.get(
"map_address_offset", settings.get("ms_map_address_offset", 0)
),
build_dir=settings.get("build_dir", settings.get("mw_build_dir", "build/")), build_dir=settings.get("build_dir", settings.get("mw_build_dir", "build/")),
show_line_numbers_default=settings.get("show_line_numbers_default", True), show_line_numbers_default=settings.get("show_line_numbers_default", True),
disassemble_all=settings.get("disassemble_all", False), disassemble_all=settings.get("disassemble_all", False),
@ -522,7 +532,7 @@ def create_config(args: argparse.Namespace, project: ProjectSettings) -> Config:
arch=arch, arch=arch,
# Build/objdump options # Build/objdump options
diff_obj=args.diff_obj, diff_obj=args.diff_obj,
objfile=args.objfile, file=args.file,
make=args.make, make=args.make,
source_old_binutils=args.source_old_binutils, source_old_binutils=args.source_old_binutils,
diff_section=args.diff_section, diff_section=args.diff_section,
@ -557,6 +567,9 @@ def get_objdump_executable(objdump_executable: Optional[str]) -> str:
"mips-linux-gnu-objdump", "mips-linux-gnu-objdump",
"mips64-elf-objdump", "mips64-elf-objdump",
"mips-elf-objdump", "mips-elf-objdump",
"sh-elf-objdump",
"sh4-linux-gnu-objdump",
"m68k-elf-objdump",
] ]
for objdump_cand in objdump_candidates: for objdump_cand in objdump_candidates:
try: try:
@ -590,7 +603,7 @@ BUFFER_CMD: List[str] = ["tail", "-c", str(10**9)]
# -i ignores case when searching # -i ignores case when searching
# -c something about how the screen gets redrawn; I don't remember the purpose # -c something about how the screen gets redrawn; I don't remember the purpose
# -#6 makes left/right arrow keys scroll by 6 characters # -#6 makes left/right arrow keys scroll by 6 characters
LESS_CMD: List[str] = ["less", "-SRic", "-#6"] LESS_CMD: List[str] = ["less", "-SRic", "-+F", "-+X", "-#6"]
DEBOUNCE_DELAY: float = 0.1 DEBOUNCE_DELAY: float = 0.1
@ -766,7 +779,6 @@ class AnsiFormatter(Formatter):
BasicFormat.STACK: Fore.YELLOW, BasicFormat.STACK: Fore.YELLOW,
BasicFormat.REGISTER: Fore.YELLOW, BasicFormat.REGISTER: Fore.YELLOW,
BasicFormat.REGISTER_CATEGORY: Fore.LIGHTYELLOW_EX, BasicFormat.REGISTER_CATEGORY: Fore.LIGHTYELLOW_EX,
BasicFormat.DELAY_SLOT: Fore.LIGHTBLACK_EX,
BasicFormat.DIFF_CHANGE: Fore.LIGHTBLUE_EX, BasicFormat.DIFF_CHANGE: Fore.LIGHTBLUE_EX,
BasicFormat.DIFF_ADD: Fore.GREEN, BasicFormat.DIFF_ADD: Fore.GREEN,
BasicFormat.DIFF_REMOVE: Fore.RED, BasicFormat.DIFF_REMOVE: Fore.RED,
@ -1271,11 +1283,7 @@ def search_map_file(
if len(find) == 1: if len(find) == 1:
names_find = re.search(r"(\S+) ... (\S+)", find[0]) names_find = re.search(r"(\S+) ... (\S+)", find[0])
assert names_find is not None assert names_find is not None
fileofs = ( fileofs = int(names_find.group(1), 16) - load_address
int(names_find.group(1), 16)
- load_address
+ project.ms_map_address_offset
)
if for_binary: if for_binary:
return None, fileofs return None, fileofs
@ -1462,7 +1470,7 @@ def dump_objfile(
if start.startswith("0"): if start.startswith("0"):
fail("numerical start address not supported with -o; pass a function name") fail("numerical start address not supported with -o; pass a function name")
objfile = config.objfile objfile = config.file
if not objfile: if not objfile:
objfile, _ = search_map_file(start, project, config, for_binary=False) objfile, _ = search_map_file(start, project, config, for_binary=False)
@ -1495,15 +1503,21 @@ def dump_objfile(
def dump_binary( def dump_binary(
start: str, end: Optional[str], config: Config, project: ProjectSettings start: str, end: Optional[str], config: Config, project: ProjectSettings
) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]: ) -> Tuple[str, ObjdumpCommand, ObjdumpCommand]:
if not project.baseimg or not project.myimg: binfile = config.file or project.myimg
if not project.baseimg or not binfile:
fail("Missing myimg/baseimg in config.") fail("Missing myimg/baseimg in config.")
if config.make: if config.make:
run_make(project.myimg, project) run_make(binfile, project)
if not os.path.isfile(binfile):
fail(f"Not able to find binary file: {binfile}")
start_addr = maybe_eval_int(start) start_addr = maybe_eval_int(start)
if start_addr is None: if start_addr is None and config.file is None:
_, start_addr = search_map_file(start, project, config, for_binary=True) _, start_addr = search_map_file(start, project, config, for_binary=True)
if start_addr is None: if start_addr is None:
fail("Not able to find function in map file.") fail("Not able to find function in map file.")
start_addr += project.map_address_offset
elif start_addr is None:
fail("Start address must be an integer expression when using binary -f")
if end is not None: if end is not None:
end_addr = eval_int(end, "End address must be an integer expression.") end_addr = eval_int(end, "End address must be an integer expression.")
else: else:
@ -1515,9 +1529,9 @@ def dump_binary(
] ]
flags2 = [f"--start-address={start_addr}", f"--stop-address={end_addr}"] flags2 = [f"--start-address={start_addr}", f"--stop-address={end_addr}"]
return ( return (
project.myimg, binfile,
(objdump_flags + flags1, project.baseimg, None), (objdump_flags + flags1, project.baseimg, None),
(objdump_flags + flags2, project.myimg, None), (objdump_flags + flags2, binfile, None),
) )
@ -1569,7 +1583,8 @@ class AsmProcessorMIPS(AsmProcessor):
# integer. # integer.
return prev, None return prev, None
before, imm, after = parse_relocated_line(prev) before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1] + reloc_addend_from_imm(imm, before, self.config.arch) addend = reloc_addend_from_imm(imm, before, self.config.arch)
repl = row.split()[-1] + addend
if "R_MIPS_LO16" in row: if "R_MIPS_LO16" in row:
repl = f"%lo({repl})" repl = f"%lo({repl})"
elif "R_MIPS_HI16" in row: elif "R_MIPS_HI16" in row:
@ -1590,6 +1605,8 @@ class AsmProcessorMIPS(AsmProcessor):
repl = f"%got({repl})" repl = f"%got({repl})"
elif "R_MIPS_CALL16" in row: elif "R_MIPS_CALL16" in row:
repl = f"%call16({repl})" repl = f"%call16({repl})"
elif "R_MIPS_LITERAL" in row:
repl = repl[:-len(addend)]
else: else:
assert False, f"unknown relocation type '{row}' for line '{prev}'" assert False, f"unknown relocation type '{row}' for line '{prev}'"
return before + repl + after, repl return before + repl + after, repl
@ -1812,6 +1829,66 @@ class AsmProcessorI686(AsmProcessor):
return mnemonic == "ret" return mnemonic == "ret"
class AsmProcessorSH2(AsmProcessor):
def __init__(self, config: Config) -> None:
super().__init__(config)
def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]:
return prev, None
def is_end_of_function(self, mnemonic: str, args: str) -> bool:
return mnemonic == "rts"
class AsmProcessorM68k(AsmProcessor):
def pre_process(
self, mnemonic: str, args: str, next_row: Optional[str]
) -> Tuple[str, str]:
# replace objdump's syntax of pointer accesses with the equivilant in AT&T syntax for readability
return mnemonic, re.sub(
r"%(sp|a[0-7]|fp|pc)@(?:(?:\((-?(?:0x[0-9a-f]+|[0-9]+)) *(,%d[0-7]:[wl])?\))|(\+)|(-))?",
r"\5\2(%\1\3)\4",
args,
)
def process_reloc(self, row: str, prev: str) -> Tuple[str, Optional[str]]:
repl = row.split()[-1]
mnemonic, args = prev.split(maxsplit=1)
addr_imm = re.search(r"(?<![#da])(0x[0-9a-f]+|[0-9]+) ?", args)
if not addr_imm:
assert False, f"failed to find address immediate for line '{prev}'"
start, end = addr_imm.span()
if "R_68K_NONE" in row:
pass
elif "R_68K_32" in row:
pass
elif "R_68K_16" in row:
pass
elif "R_68K_8" in row:
pass
elif "R_68K_GOT32O" in row:
repl = "@GOT"
elif "R_68K_GOT16O" in row:
repl += "@GOT"
elif "R_68K_GOT8O" in row:
repl += "@GOT"
elif "R_68K_GOT32" in row:
repl += "@GOTPC"
elif "R_68K_GOT16" in row:
repl += "@GOTPC"
elif "R_68K_GOT8" in row:
repl += "@GOTPC"
else:
assert False, f"unknown relocation type '{row}' for line '{prev}'"
return f"{mnemonic}\t{args[:start]+repl+args[end:]}", repl
def is_end_of_function(self, mnemonic: str, args: str) -> bool:
return mnemonic == "rts" or mnemonic == "rte" or mnemonic == "rtr"
@dataclass @dataclass
class ArchSettings: class ArchSettings:
name: str name: str
@ -2006,6 +2083,48 @@ I686_BRANCH_INSTRUCTIONS = {
"jz", "jz",
} }
SH2_BRANCH_INSTRUCTIONS = {
"bf",
"bf.s",
"bt",
"bt.s",
"bra",
"bsr",
}
M68K_CONDS = {
"ra",
"cc",
"cs",
"eq",
"ge",
"gt",
"hi",
"le",
"ls",
"lt",
"mi",
"ne",
"pl",
"vc",
"vs",
}
M68K_BRANCH_INSTRUCTIONS = {
f"{prefix}{cond}{suffix}"
for prefix in {"b", "db"}
for cond in M68K_CONDS
for suffix in {"s", "w"}
}.union(
{
"dbt",
"dbf",
"bsrw",
"bsrs",
}
)
MIPS_SETTINGS = ArchSettings( MIPS_SETTINGS = ArchSettings(
name="mips", name="mips",
re_int=re.compile(r"[0-9]+"), re_int=re.compile(r"[0-9]+"),
@ -2127,6 +2246,72 @@ I686_SETTINGS = ArchSettings(
proc=AsmProcessorI686, proc=AsmProcessorI686,
) )
SH2_SETTINGS = ArchSettings(
name="sh2",
# match -128-127 preceded by a '#' with a ',' after (8 bit immediates)
re_int=re.compile(r"(?<=#)(-?(?:1[01][0-9]|12[0-8]|[1-9][0-9]?|0))(?=,)"),
# match <text>, match ! and after
re_comment=re.compile(r"<.*?>|!.*"),
# - r0-r15 general purpose registers, r15 is stack pointer during exceptions
# - sr, gbr, vbr - control registers
# - mach, macl, pr, pc - system registers
re_reg=re.compile(r"r1[0-5]|r[0-9]"),
# sh2 has pc-relative and gbr-relative but not stack-pointer-relative
re_sprel=re.compile(r"(?<=,)([0-9]+|0x[0-9a-f]+)\(sp\)"),
# max immediate size is 8-bit
re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"),
re_imm=re.compile(r"\b0[xX][0-9a-fA-F]+\b"),
# https://github.com/bminor/binutils-gdb/blob/master/bfd/elf32-sh-relocs.h#L21
re_reloc=re.compile(r"R_SH_"),
arch_flags=["-m", "sh2"],
branch_instructions=SH2_BRANCH_INSTRUCTIONS,
instructions_with_address_immediates=SH2_BRANCH_INSTRUCTIONS.union(
{"bf", "bf.s", "bt", "bt.s", "bra", "bsr"}
),
delay_slot_instructions=SH2_BRANCH_INSTRUCTIONS.union(
{"bf.s", "bt.s", "bra", "braf", "bsr", "bsrf", "jmp", "jsr", "rts"}
),
proc=AsmProcessorSH2,
)
SH4_SETTINGS = replace(
SH2_SETTINGS,
name="sh4",
# - fr0-fr15, dr0-dr14, xd0-xd14, fv0-fv12 FP registers
# dr/xd registers can only be even-numbered, and fv registers can only be a multiple of 4
re_reg=re.compile(
r"r1[0-5]|r[0-9]|fr1[0-5]|fr[0-9]|dr[02468]|dr1[024]|xd[02468]|xd1[024]|fv[048]|fv12"
),
arch_flags=["-m", "sh4"],
)
SH4EL_SETTINGS = replace(SH4_SETTINGS, name="sh4el", big_endian=False)
M68K_SETTINGS = ArchSettings(
name="m68k",
re_int=re.compile(r"[0-9]+"),
# '|' is used by assemblers, but is not used by objdump
re_comment=re.compile(r"<.*>"),
# Includes:
# - d0-d7 data registers
# - a0-a6 address registers
# - fp0-fp7 floating-point registers
# - usp (user sp)
# - fp, sr, ccr
# - fpcr, fpsr, fpiar
re_reg=re.compile(r"%\b(d[0-7]|a[0-6]|usp|fp([0-7]|cr|sr|iar)?|sr|ccr)(:[wl])?\b"),
# This matches all stack accesses that do not use an index register
re_sprel=re.compile(r"-?(0x[0-9a-f]+|[0-9]+)(?=\((%sp|%a7)\))"),
re_imm=re.compile(r"#?-?\b(0x[0-9a-f]+|[0-9]+)(?!\()"),
re_large_imm=re.compile(r"#?-?([1-9][0-9]{2,}|0x[0-9a-f]{3,})"),
re_reloc=re.compile(r"R_68K_"),
arch_flags=["-m", "m68k"],
branch_instructions=M68K_BRANCH_INSTRUCTIONS,
# Pretty much every instruction can take an address immediate
instructions_with_address_immediates=M68K_BRANCH_INSTRUCTIONS.union("jmp", "jsr"),
proc=AsmProcessorM68k,
)
ARCH_SETTINGS = [ ARCH_SETTINGS = [
MIPS_SETTINGS, MIPS_SETTINGS,
MIPSEL_SETTINGS, MIPSEL_SETTINGS,
@ -2136,11 +2321,21 @@ ARCH_SETTINGS = [
AARCH64_SETTINGS, AARCH64_SETTINGS,
PPC_SETTINGS, PPC_SETTINGS,
I686_SETTINGS, I686_SETTINGS,
SH2_SETTINGS,
SH4_SETTINGS,
SH4EL_SETTINGS,
M68K_SETTINGS,
] ]
def hexify_int(row: str, pat: Match[str], arch: ArchSettings) -> str: def hexify_int(row: str, pat: Match[str], arch: ArchSettings) -> str:
full = pat.group(0) full = pat.group(0)
# sh2/sh4 only has 8-bit immediates, just convert them uniformly without
# any -hex stuff
if arch.name == "sh2" or arch.name == "sh4" or arch.name == "sh4el":
return hex(int(full) & 0xFF)
if len(full) <= 1: if len(full) <= 1:
# leave one-digit ints alone # leave one-digit ints alone
return full return full
@ -2220,16 +2415,15 @@ class Line:
def process(dump: str, config: Config) -> List[Line]: def process(dump: str, config: Config) -> List[Line]:
arch = config.arch arch = config.arch
processor = arch.proc(config) processor = arch.proc(config)
skip_next = False
source_lines = [] source_lines = []
source_filename = None source_filename = None
source_line_num = None source_line_num = None
rets_remaining = config.stop_at_ret
i = 0 i = 0
num_instr = 0 num_instr = 0
data_refs: Dict[int, Dict[str, List[int]]] = defaultdict(lambda: defaultdict(list)) data_refs: Dict[int, Dict[str, List[int]]] = defaultdict(lambda: defaultdict(list))
output: List[Line] = [] output: List[Line] = []
stop_after_delay_slot = False
lines = dump.split("\n") lines = dump.split("\n")
while i < len(lines): while i < len(lines):
row = lines[i] row = lines[i]
@ -2364,17 +2558,8 @@ def process(dump: str, config: Config) -> List[Line]:
if not config.score_stack_differences: if not config.score_stack_differences:
scorable_line = re.sub(arch.re_sprel, "addr(sp)", scorable_line) scorable_line = re.sub(arch.re_sprel, "addr(sp)", scorable_line)
if skip_next:
skip_next = False
row = "<delay-slot>"
mnemonic = "<delay-slot>"
scorable_line = "<delay-slot>"
if mnemonic in arch.branch_likely_instructions:
skip_next = True
row = re.sub(arch.re_reg, "<reg>", row) row = re.sub(arch.re_reg, "<reg>", row)
row = re.sub(arch.re_sprel, "addr(sp)", row) row = re.sub(arch.re_sprel, "addr(sp)", row)
row_with_imm = row
if mnemonic in arch.instructions_with_address_immediates: if mnemonic in arch.instructions_with_address_immediates:
row = row.strip() row = row.strip()
row, _ = split_off_address(row) row, _ = split_off_address(row)
@ -2414,8 +2599,10 @@ def process(dump: str, config: Config) -> List[Line]:
num_instr += 1 num_instr += 1
source_lines = [] source_lines = []
if config.stop_at_ret and processor.is_end_of_function(mnemonic, args): if rets_remaining and processor.is_end_of_function(mnemonic, args):
break rets_remaining -= 1
if rets_remaining == 0:
break
processor.post_process(output) processor.post_process(output)
return output return output
@ -2509,7 +2696,7 @@ def diff_sequences(
try: try:
rem1 = remap(seq1) rem1 = remap(seq1)
rem2 = remap(seq2) rem2 = remap(seq2)
except ValueError as e: except ValueError:
if len(seq1) + len(seq2) < 0x110000: if len(seq1) + len(seq2) < 0x110000:
raise raise
# If there are too many unique elements, chr() doesn't work. # If there are too many unique elements, chr() doesn't work.
@ -2776,13 +2963,6 @@ def do_diff(lines1: List[Line], lines2: List[Line], config: Config) -> Diff:
# the diff, and don't just happen to have the are the same address # the diff, and don't just happen to have the are the same address
# by accident. # by accident.
pass pass
elif line1.diff_row == "<delay-slot>":
# Don't draw attention to differing branch-likely delay slots: they
# typically mirror the branch destination - 1 so the real difference
# is elsewhere. Still, do mark them as different to avoid confusion.
# No need to consider branches because delay slots can't branch.
out1 = out1.reformat(BasicFormat.DELAY_SLOT)
out2 = out2.reformat(BasicFormat.DELAY_SLOT)
else: else:
mnemonic = line1.original.split()[0] mnemonic = line1.original.split()[0]
branchless1, address1 = out1.plain(), "" branchless1, address1 = out1.plain(), ""
@ -3131,7 +3311,7 @@ def align_diffs(old_diff: Diff, new_diff: Diff, config: Config) -> TableData:
def diff_line_to_table_line(line: Tuple[OutputLine, ...]) -> TableLine: def diff_line_to_table_line(line: Tuple[OutputLine, ...]) -> TableLine:
cells = [ cells = [
(line[0].base or Text(), line[0].line1) (line[0].base or Text(), line[0].line1),
] ]
for ol in line[1:]: for ol in line[1:]:
cells.append((ol.fmt2, ol.line2)) cells.append((ol.fmt2, ol.line2))
@ -3433,9 +3613,9 @@ def main() -> None:
elif not args.watch: elif not args.watch:
display.run_sync() display.run_sync()
else: else:
if not args.make: if not args.make and not args.agree:
yn = input( yn = input(
"Warning: watch-mode (-w) enabled without auto-make (-m). " "Warning: watch-mode (-w) enabled without auto-make (-m) or agree-all (-y). "
"You will have to run make manually. Ok? (Y/n) " "You will have to run make manually. Ok? (Y/n) "
) )
if yn.lower() == "n": if yn.lower() == "n":

View File

@ -11,7 +11,7 @@ warn_return_any = True
warn_unused_ignores = True warn_unused_ignores = True
ignore_missing_imports = True ignore_missing_imports = True
python_version = 3.6 python_version = 3.6
files = diff.py files = diff.py, test.py
[mypy-diff_settings] [mypy-diff_settings]
ignore_errors = True ignore_errors = True

321
tools/asm-differ/poetry.lock generated Normal file
View File

@ -0,0 +1,321 @@
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
[[package]]
name = "ansiwrap"
version = "0.8.4"
description = "textwrap, but savvy to ANSI colors and styles"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "ansiwrap-0.8.4-py2.py3-none-any.whl", hash = "sha256:7b053567c88e1ad9eed030d3ac41b722125e4c1271c8a99ade797faff1f49fb1"},
{file = "ansiwrap-0.8.4.zip", hash = "sha256:ca0c740734cde59bf919f8ff2c386f74f9a369818cdc60efe94893d01ea8d9b7"},
]
[package.dependencies]
textwrap3 = ">=0.9.2"
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "cxxfilt"
version = "0.3.0"
description = "Python interface to c++filt / abi::__cxa_demangle"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "cxxfilt-0.3.0-py2.py3-none-any.whl", hash = "sha256:774e85a8d0157775ed43276d89397d924b104135762d86b3a95f81f203094e07"},
{file = "cxxfilt-0.3.0.tar.gz", hash = "sha256:7df6464ba5e8efbf0d8974c0b2c78b32546676f06059a83515dbdfa559b34214"},
]
[package.extras]
test = ["pytest (>=3.0.0)"]
[[package]]
name = "levenshtein"
version = "0.20.9"
description = "Python extension for computing string edit distances and similarities."
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "Levenshtein-0.20.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:105c239ec786750cd5136991c58196b440cc39b6acf3ec8227f6562c9a94e4b9"},
{file = "Levenshtein-0.20.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f7728bea7fe6dc55ceecde0dcda4287e74fe3b6733ad42530f46aaa8d2f81d0"},
{file = "Levenshtein-0.20.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc7eca755c13c92814c8cce8175524cf764ce38f39228b602f59eac58cfdc51a"},
{file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8a552e79d053dc1324fb90d342447fd4e15736f4cbc5363b6fbd5577f53dce9"},
{file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5474b2681ee0b7944fb1e7fe281cd44e2dfe75b03ba4558dca49c96fa0861b62"},
{file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:56e132c203b0dd8fc72a33e791c39ad0d5a25bcf24b130a1e202abbf489a3e75"},
{file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3badc94708ac05b405e795fde58a53272b90a9ee6099ecd54a345658b7b812e1"},
{file = "Levenshtein-0.20.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48b9b3ae095b14dad7bc4bd219c7cd9113a7aa123a033337c85b00fe2ed565d3"},
{file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0d3a1f7328c91caeb1f857ddd2787e3f19d60cc2c688339d249ca8841da61454"},
{file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ef67c50428c99caf67d31bd209da21d9378da5f0cc3ad4f7bafb6caa78aee6f2"},
{file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:47f6d1592c0891f7355e38a302becd233336ca2f55f9a8be3a8635f946a6784f"},
{file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2891019740e874f05e0349e9f27b6af8ad837b1612f42e9c90c296d54d1404fd"},
{file = "Levenshtein-0.20.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c554704eec4f4ba742febdcc79a85491f8f9a1d493cb103bb2af18536d6cf122"},
{file = "Levenshtein-0.20.9-cp310-cp310-win32.whl", hash = "sha256:7628e356b3f9c78ad7272c3b9137f0641a1368849e749ff6f2c8fe372795806b"},
{file = "Levenshtein-0.20.9-cp310-cp310-win_amd64.whl", hash = "sha256:ba2bafe3511194a37044cae4e7d328cca70657933052691c37eba2ca428a379d"},
{file = "Levenshtein-0.20.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7605a94145198d19fdaaa7e29c0f8a56ad719b12386f3ae8cd8ed4cb9fa6c2e4"},
{file = "Levenshtein-0.20.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29db4dabfad2ddf33c7986eb6fd525c7587cca4c4d9e187365cff0a5281f5a35"},
{file = "Levenshtein-0.20.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:965336c1772a4fc5fb2686a2a0bfaf3455dced96f19f50f278da8bc139076d31"},
{file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67235753035ac898d6475c0b29540521018db2e0027a3c1deb9aa0af0a84fd74"},
{file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:120dca58136aee3d8c7b190e30db7b6a6eb9579ea5712df84ad076a389801743"},
{file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6496ea66a6f755e48c0d82f1eee396d16edcd5592d4b3677d26fa789a636a728"},
{file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0af20327acc2c904d11611cb3a0d8d17f80c279a12e0b84189eafc35297186d"},
{file = "Levenshtein-0.20.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d2f891ef53afbab6cf2eeb92ff13151884d17dc80a2d6d3c7ae74d7738b772"},
{file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2ab9c72380582bf4745d1c5b055b1df0c85f7a980a04bd7603a855dd91478c0f"},
{file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6de13be3eb5ac48053fb1635a7b4daa936b9114ad4b264942e9eb709fcaa41dd"},
{file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a9fc296860588251d8d72b4f4637cca4eef7351e042a7a23d44e6385aef1e160"},
{file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:35777b20fe35858248c22da37984469e6dd1278f55d17c53378312853d5d683d"},
{file = "Levenshtein-0.20.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6b9e0642ddb4c431f77c38cec9edbd0317e26c3f37d072ccf281ab58926dce69"},
{file = "Levenshtein-0.20.9-cp311-cp311-win32.whl", hash = "sha256:f88ec322d86d3cc9d3936dbf6b421ad813950c2658599d48ac4ede59f2a6047e"},
{file = "Levenshtein-0.20.9-cp311-cp311-win_amd64.whl", hash = "sha256:2907a6888455f9915d5b656f5d058f63eaf6063b2c7f0f1ff6bc05706ae5bc39"},
{file = "Levenshtein-0.20.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6bcebc79760be08488cb921732af34ade6abc7476a94866881c68b45ec4b6c82"},
{file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47d8d4f3825d1d8f3b19382537a8536e689cf57aaa224d2cb4f44cf844811885"},
{file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d40e18a5817ee7f0675401613a26c492fd4ea68d2103c1480fb5a6ab1b8763d"},
{file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d258f3d44f6bac17f33002fea34570049507d3476c3716b5267170c666b20b4"},
{file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c621e0c389546147ed43c33ca4168de0f91c920508ab8a94a400835fa084f486"},
{file = "Levenshtein-0.20.9-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57a31527dc7994353091626e62b7d82d53290cb00df48d3e5d29cb291fb4c03c"},
{file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:129c8f192e656b7c2c543bf0d704d677720771b8bc2f30c50db02fbc2001bac2"},
{file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5a01fca58255be6bf724a40af2575d7cf644c099c28a00d1f5f6a81675e60e7d"},
{file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:4c13749ea39a228f05d5bd9d473e76f726fc2dcd493cafc322f740921a6eeffb"},
{file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:69daa0f8eefa5b947255a81346741ed86fe7030e0909741dbd978e38b30da3fd"},
{file = "Levenshtein-0.20.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fcc78a73ed423bbb09ac902dd2e1ff1094d159d1c6766e5e52da5f376a4cba18"},
{file = "Levenshtein-0.20.9-cp36-cp36m-win32.whl", hash = "sha256:d82ae57982a9f33c55778f1f0f63d5e51e291aee236abed3b90497578b944202"},
{file = "Levenshtein-0.20.9-cp36-cp36m-win_amd64.whl", hash = "sha256:4082379b406752fc1173ed1f8c3a122c5d5491e10e564ed721602e4e049e3d4c"},
{file = "Levenshtein-0.20.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb499783b7126e6fc45c39ab34c8114148425c5d975b1ce35e6c47c0eda58a94"},
{file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce747b296aad3bd8a563cccf2119cf37bf72f668076bfdad6ec55f0a0596dd9"},
{file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1347c3ebbe8f42f7a487e8d23a95bde6529379b4939ad51d32246d001565c499"},
{file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a2f1c1e8360603a6da29416da61d1907a27656843e269413091c8c3a3e6286e"},
{file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73c1caaedbee3617fd29139aac8dab7743776b59c3c1fed2790308ecb43c7b25"},
{file = "Levenshtein-0.20.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1f24133df69f8b618fc508d6023695130ad3c3c8968ef43aaeca21835eb337a"},
{file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cf7260722f8170c09af5cfa714bb45626a4dfc85d71d1c1c9c52c2a6901cc501"},
{file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:01668178fd9244df290db0340293982fe7641162a12a35ad9ffb3fe145ce6377"},
{file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e46f9d3483dc4991ac60ff3711b0d40f93e352cc8edc16b68df57ccc472bd6c"},
{file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:680cd250dc1875eb80cf2a0cca742bd13f6f9ab11c48317244fcc483eba1dd67"},
{file = "Levenshtein-0.20.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2346e2f7dfbbc2936bd81e19f7734984e72486ffc086760c897b39b9f674b2fa"},
{file = "Levenshtein-0.20.9-cp37-cp37m-win32.whl", hash = "sha256:7f31bcf257fec9719d0d97185c419d315f6f20a194f0b442919e352d19418b2e"},
{file = "Levenshtein-0.20.9-cp37-cp37m-win_amd64.whl", hash = "sha256:48262bc9830ad60de96411fcb2e96a522c7206e7069169e04d89dd79364a7722"},
{file = "Levenshtein-0.20.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eba5696e1f8e8da225498fd1d743886d639400cafd0e5be3c553978cbb54c345"},
{file = "Levenshtein-0.20.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:679333188f9791c85109d2981e97e8721a99b2b975b5c52d16aca50ac9c70757"},
{file = "Levenshtein-0.20.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:06c9cfc61cf66833692d1ed258ec5a0871221b0779f1281c32a10348c492e2c5"},
{file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5d80d949168df406f2ac9ade1a5d0419cef0a8df611c8c2efe88f0248c9d0c0"},
{file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9275c6e601ff7f659116e2235e8585950c9c39d72504006077be85bf27950b35"},
{file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6414eea342d9632045e12b66bef043dbc6557189a283dc4dcc5966f63fa48998"},
{file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56571c58700600a382ecdf3f9efcb132ed16a0476cbb4e23a9478ab0ae788fd9"},
{file = "Levenshtein-0.20.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7ccb76ffd9b851384f9cf1595b90b17cae46f0ab895e234de11ea48f9d9f73a"},
{file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109172943cff7fb10f28a9eb819eb3eaf9c88fe38661fb1d0f230a8ae68a615c"},
{file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:534c8bbdfd033fa20575d57332d9ac0447b5afbeca7db975ba169762ece2051f"},
{file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:381a725963c392585135654caa3c7fc32cb1755ed977fb9db72e8838fee261be"},
{file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7e4a44b1223980a9880e6f2bbf19121a125928580df9e4e81207199190343e11"},
{file = "Levenshtein-0.20.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc0ced58ee6d07351cde140a7ec88e5f2ceb053c805af1f90514d21914d21cad"},
{file = "Levenshtein-0.20.9-cp38-cp38-win32.whl", hash = "sha256:5eec0868ffcd825564dd5e3399305eaa159220554d1aedbff13af0de1fe01f6c"},
{file = "Levenshtein-0.20.9-cp38-cp38-win_amd64.whl", hash = "sha256:e9db476e40a3aa184631d102b716a019f70837eb0fcdd5b5d1504f099f91359c"},
{file = "Levenshtein-0.20.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d5a20ecc20a09a32c72128c43d7df23877a2469b3c17780ae83f9a9d55873c08"},
{file = "Levenshtein-0.20.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b7b772f2f62a19a15ccb1b09c6c7754ca7430bb7e19d4ca4ff232958786873b"},
{file = "Levenshtein-0.20.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af92326b90ea6fe4521cf6a5dfe450e21150393c573ef3ad9ee446f1009fbfbd"},
{file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b48554dad328e198a636f937e2f4c057aac8e4bfcb8467b10e0f5daa94307b17"},
{file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82304821e128d5453d1755d1c2f3d9cdf75e9def3517cf913b09df174e20283b"},
{file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2052357c5da195ede7dbc81a4e3408ebd6374a1ff1b86a0a9d8b8ce9562b32c3"},
{file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d60c6b47ccd6841c990418f7f4f58c28f7da9b07b81eaafc99b836cf351df1"},
{file = "Levenshtein-0.20.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dc2194c917e4466cb604580b16e42286f04e3fe0424489459e68f0834f5c527"},
{file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb1e20965d759d89318cac7ff7eb045eb1fafcb5c3fa3047a23f6ae20c810ad7"},
{file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:74e959035da10a54e7a2eee28408eff672297ce96cdadd6f4a2f269a06e395c4"},
{file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4a441b23d9704f57eb34af6a300ae5c335b9e77e6a065ada36ca69d6fc582af9"},
{file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:f59470c49114a5da064712a427317f2b1fa5bb89aa2dfd0e300f8289e26aec28"},
{file = "Levenshtein-0.20.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:06191f5d0527e3224107aea260b5cffc8a78722e0efb4e793f0e45c449b813a2"},
{file = "Levenshtein-0.20.9-cp39-cp39-win32.whl", hash = "sha256:3235c461904fe94b4f62fee78a1658c1316344411c81b02400c27d692a893f8f"},
{file = "Levenshtein-0.20.9-cp39-cp39-win_amd64.whl", hash = "sha256:8b852def43d165c2f2b468239d66b847d9e6f52a775fc657773ced04d26062bd"},
{file = "Levenshtein-0.20.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f674cc75f127692525563155e500a3fa16aaf24dafd33a9bcda46e2979f793a1"},
{file = "Levenshtein-0.20.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a34e3fd21acb31fcd29a0c8353dca74dfbb59957210a6f142505907a9dff3d59"},
{file = "Levenshtein-0.20.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0ddddf2beafd1a2e17a87f80be562a7f7478e6098ccfc15de4c879972dfa2f9"},
{file = "Levenshtein-0.20.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9649af1a896a4a7fc7f6f1fd093e8a92f463297f56c7bd0f8d7d16dfabeb236d"},
{file = "Levenshtein-0.20.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d7bd7f25336849027fbe5ed32b6ffd404436727d78a014e348dcd17347c73fd8"},
{file = "Levenshtein-0.20.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0371d996ae81089296f42b6e886c7bf138d1cb0f002b0c724a9e5d689b29b5a0"},
{file = "Levenshtein-0.20.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7e00e2fda9f225b5f4537647f6195cf220d468532739d3390eaf082b1d76c87"},
{file = "Levenshtein-0.20.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1600f5ebe2f2aebf13e88cf488ec2e5ce25f7a42b5846335018693baf4ea63bd"},
{file = "Levenshtein-0.20.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bcd59fcf06aaedda98da185ec289dc2c2c9922ce789f6a9c101709d4a22cac9"},
{file = "Levenshtein-0.20.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:1549e307028fa5c3a8cf28ae8bcb1f6072df2abf7f36b9d7adf7fd60690fe372"},
{file = "Levenshtein-0.20.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:795f2e95d09a33c66c73cd49be3ee632fb4b8c41be72c0cb8df29a329ce7d111"},
{file = "Levenshtein-0.20.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:726bfb361d3b6786bea31392752f0ffcca568db7dc3f1e274f1b529489b8ad05"},
{file = "Levenshtein-0.20.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0fd315132786375de532355fa06b2f11c4b4af5784b7e064dc54b6ee0c3281"},
{file = "Levenshtein-0.20.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0674bc0549d5ea9edb934b3b03a160a116cc410feb5739a51f9c4f618ee674e3"},
{file = "Levenshtein-0.20.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1ef8f3ecdfca5d6f0538226338d58617270439a1cc9b6cacb30a388984bb1608"},
{file = "Levenshtein-0.20.9.tar.gz", hash = "sha256:70a8ad5e28bb76d87da1eb3f31de940836596547d6d01317c2289f5b7cd0b0ea"},
]
[package.dependencies]
rapidfuzz = ">=2.3.0,<3.0.0"
[[package]]
name = "rapidfuzz"
version = "2.15.1"
description = "rapid fuzzy string matching"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "rapidfuzz-2.15.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fc0bc259ebe3b93e7ce9df50b3d00e7345335d35acbd735163b7c4b1957074d3"},
{file = "rapidfuzz-2.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d59fb3a410d253f50099d7063855c2b95df1ef20ad93ea3a6b84115590899f25"},
{file = "rapidfuzz-2.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c525a3da17b6d79d61613096c8683da86e3573e807dfaecf422eea09e82b5ba6"},
{file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4deae6a918ecc260d0c4612257be8ba321d8e913ccb43155403842758c46fbe"},
{file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2577463d10811386e704a3ab58b903eb4e2a31b24dfd9886d789b0084d614b01"},
{file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f67d5f56aa48c0da9de4ab81bffb310683cf7815f05ea38e5aa64f3ba4368339"},
{file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7927722ff43690e52b3145b5bd3089151d841d350c6f8378c3cfac91f67573a"},
{file = "rapidfuzz-2.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6534afc787e32c4104f65cdeb55f6abe4d803a2d0553221d00ef9ce12788dcde"},
{file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d0ae6ec79a1931929bb9dd57bc173eb5ba4c7197461bf69e3a34b6dd314feed2"},
{file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be7ccc45c4d1a7dfb595f260e8022a90c6cb380c2a346ee5aae93f85c96d362b"},
{file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:8ba013500a2b68c64b2aecc5fb56a2dad6c2872cf545a0308fd044827b6e5f6a"},
{file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4d9f7d10065f657f960b48699e7dddfce14ab91af4bab37a215f0722daf0d716"},
{file = "rapidfuzz-2.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7e24a1b802cea04160b3fccd75d2d0905065783ebc9de157d83c14fb9e1c6ce2"},
{file = "rapidfuzz-2.15.1-cp310-cp310-win32.whl", hash = "sha256:dffdf03499e0a5b3442951bb82b556333b069e0661e80568752786c79c5b32de"},
{file = "rapidfuzz-2.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d150d90a7c6caae7962f29f857a4e61d42038cfd82c9df38508daf30c648ae7"},
{file = "rapidfuzz-2.15.1-cp310-cp310-win_arm64.whl", hash = "sha256:87c30e9184998ff6eb0fa9221f94282ce7c908fd0da96a1ef66ecadfaaa4cdb7"},
{file = "rapidfuzz-2.15.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6986413cb37035eb796e32f049cbc8c13d8630a4ac1e0484e3e268bb3662bd1b"},
{file = "rapidfuzz-2.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a72f26e010d4774b676f36e43c0fc8a2c26659efef4b3be3fd7714d3491e9957"},
{file = "rapidfuzz-2.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b5cd54c98a387cca111b3b784fc97a4f141244bbc28a92d4bde53f164464112e"},
{file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7fac7c3da39f93e6b2ebe386ed0ffe1cefec91509b91857f6e1204509e931f"},
{file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f976e76ac72f650790b3a5402431612175b2ac0363179446285cb3c901136ca9"},
{file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abde47e1595902a490ed14d4338d21c3509156abb2042a99e6da51f928e0c117"},
{file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca8f1747007a3ce919739a60fa95c5325f7667cccf6f1c1ef18ae799af119f5e"},
{file = "rapidfuzz-2.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c35da09ab9797b020d0d4f07a66871dfc70ea6566363811090353ea971748b5a"},
{file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a3a769ca7580686a66046b77df33851b3c2d796dc1eb60c269b68f690f3e1b65"},
{file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d50622efefdb03a640a51a6123748cd151d305c1f0431af762e833d6ffef71f0"},
{file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b7461b0a7651d68bc23f0896bffceea40f62887e5ab8397bf7caa883592ef5cb"},
{file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:074ee9e17912e025c72a5780ee4c7c413ea35cd26449719cc399b852d4e42533"},
{file = "rapidfuzz-2.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7025fb105a11f503943f17718cdb8241ea3bb4d812c710c609e69bead40e2ff0"},
{file = "rapidfuzz-2.15.1-cp311-cp311-win32.whl", hash = "sha256:2084d36b95139413cef25e9487257a1cc892b93bd1481acd2a9656f7a1d9930c"},
{file = "rapidfuzz-2.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:5a738fcd24e34bce4b19126b92fdae15482d6d3a90bd687fd3d24ce9d28ce82d"},
{file = "rapidfuzz-2.15.1-cp311-cp311-win_arm64.whl", hash = "sha256:dc3cafa68cfa54638632bdcadf9aab89a3d182b4a3f04d2cad7585ed58ea8731"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3c53d57ba7a88f7bf304d4ea5a14a0ca112db0e0178fff745d9005acf2879f7d"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6ee758eec4cf2215dc8d8eafafcea0d1f48ad4b0135767db1b0f7c5c40a17dd"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d93ba3ae59275e7a3a116dac4ffdb05e9598bf3ee0861fecc5b60fb042d539e"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c3ff75e647908ddbe9aa917fbe39a112d5631171f3fcea5809e2363e525a59d"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d89c421702474c6361245b6b199e6e9783febacdbfb6b002669e6cb3ef17a09"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f69e6199fec0f58f9a89afbbaea78d637c7ce77f656a03a1d6ea6abdc1d44f8"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:41dfea282844d0628279b4db2929da0dacb8ac317ddc5dcccc30093cf16357c1"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2dd03477feefeccda07b7659dd614f6738cfc4f9b6779dd61b262a73b0a9a178"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:5efe035aa76ff37d1b5fa661de3c4b4944de9ff227a6c0b2e390a95c101814c0"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ed2cf7c69102c7a0a06926d747ed855bc836f52e8d59a5d1e3adfd980d1bd165"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a0e441d4c2025110ec3eba5d54f11f78183269a10152b3a757a739ffd1bb12bf"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-win32.whl", hash = "sha256:a4a54efe17cc9f53589c748b53f28776dfdfb9bc83619685740cb7c37985ac2f"},
{file = "rapidfuzz-2.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:bb8318116ecac4dfb84841d8b9b461f9bb0c3be5b616418387d104f72d2a16d1"},
{file = "rapidfuzz-2.15.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e9296c530e544f68858c3416ad1d982a1854f71e9d2d3dcedb5b216e6d54f067"},
{file = "rapidfuzz-2.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:49c4bcdb9238f11f8c4eba1b898937f09b92280d6f900023a8216008f299b41a"},
{file = "rapidfuzz-2.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebb40a279e134bb3fef099a8b58ed5beefb201033d29bdac005bddcdb004ef71"},
{file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7381c11cb590bbd4e6f2d8779a0b34fdd2234dfa13d0211f6aee8ca166d9d05"},
{file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfdcdedfd12a0077193f2cf3626ff6722c5a184adf0d2d51f1ec984bf21c23c3"},
{file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85bece1ec59bda8b982bd719507d468d4df746dfb1988df11d916b5e9fe19e8"},
{file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1b393f4a1eaa6867ffac6aef58cfb04bab2b3d7d8e40b9fe2cf40dd1d384601"},
{file = "rapidfuzz-2.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53de456ef020a77bf9d7c6c54860a48e2e902584d55d3001766140ac45c54bc7"},
{file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2492330bc38b76ed967eab7bdaea63a89b6ceb254489e2c65c3824efcbf72993"},
{file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:099e4c6befaa8957a816bdb67ce664871f10aaec9bebf2f61368cf7e0869a7a1"},
{file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:46599b2ad4045dd3f794a24a6db1e753d23304699d4984462cf1ead02a51ddf3"},
{file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:591f19d16758a3c55c9d7a0b786b40d95599a5b244d6eaef79c7a74fcf5104d8"},
{file = "rapidfuzz-2.15.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed17359061840eb249f8d833cb213942e8299ffc4f67251a6ed61833a9f2ea20"},
{file = "rapidfuzz-2.15.1-cp38-cp38-win32.whl", hash = "sha256:aa1e5aad325168e29bf8e17006479b97024aa9d2fdbe12062bd2f8f09080acf8"},
{file = "rapidfuzz-2.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:c2bb68832b140c551dbed691290bef4ee6719d4e8ce1b7226a3736f61a9d1a83"},
{file = "rapidfuzz-2.15.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3fac40972cf7b6c14dded88ae2331eb50dfbc278aa9195473ef6fc6bfe49f686"},
{file = "rapidfuzz-2.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0e456cbdc0abf39352800309dab82fd3251179fa0ff6573fa117f51f4e84be8"},
{file = "rapidfuzz-2.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:22b9d22022b9d09fd4ece15102270ab9b6a5cfea8b6f6d1965c1df7e3783f5ff"},
{file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46754fe404a9a6f5cbf7abe02d74af390038d94c9b8c923b3f362467606bfa28"},
{file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91abb8bf7610efe326394adc1d45e1baca8f360e74187f3fa0ef3df80cdd3ba6"},
{file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e40a2f60024f9d3c15401e668f732800114a023f3f8d8c40f1521a62081ff054"},
{file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a48ee83916401ac73938526d7bd804e01d2a8fe61809df7f1577b0b3b31049a3"},
{file = "rapidfuzz-2.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71580052f9dbac443c02f60484e5a2e5f72ad4351b84b2009fbe345b1f38422"},
{file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:82b86d5b8c1b9bcbc65236d75f81023c78d06a721c3e0229889ff4ed5c858169"},
{file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fc4528b7736e5c30bc954022c2cf410889abc19504a023abadbc59cdf9f37cae"},
{file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e1e0e569108a5760d8f01d0f2148dd08cc9a39ead79fbefefca9e7c7723c7e88"},
{file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:94e1c97f0ad45b05003806f8a13efc1fc78983e52fa2ddb00629003acf4676ef"},
{file = "rapidfuzz-2.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47e81767a962e41477a85ad7ac937e34d19a7d2a80be65614f008a5ead671c56"},
{file = "rapidfuzz-2.15.1-cp39-cp39-win32.whl", hash = "sha256:79fc574aaf2d7c27ec1022e29c9c18f83cdaf790c71c05779528901e0caad89b"},
{file = "rapidfuzz-2.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:f3dd4bcef2d600e0aa121e19e6e62f6f06f22a89f82ef62755e205ce14727874"},
{file = "rapidfuzz-2.15.1-cp39-cp39-win_arm64.whl", hash = "sha256:cac095cbdf44bc286339a77214bbca6d4d228c9ebae3da5ff6a80aaeb7c35634"},
{file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b89d1126be65c85763d56e3b47d75f1a9b7c5529857b4d572079b9a636eaa8a7"},
{file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7460e91168229768be882ea365ba0ac7da43e57f9416e2cfadc396a7df3c2"},
{file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c33c03e7092642c38f8a15ca2d8fc38da366f2526ec3b46adf19d5c7aa48ba"},
{file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040faca2e26d9dab5541b45ce72b3f6c0e36786234703fc2ac8c6f53bb576743"},
{file = "rapidfuzz-2.15.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:6e2a3b23e1e9aa13474b3c710bba770d0dcc34d517d3dd6f97435a32873e3f28"},
{file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2e597b9dfd6dd180982684840975c458c50d447e46928efe3e0120e4ec6f6686"},
{file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d14752c9dd2036c5f36ebe8db5f027275fa7d6b3ec6484158f83efb674bab84e"},
{file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558224b6fc6124d13fa32d57876f626a7d6188ba2a97cbaea33a6ee38a867e31"},
{file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c89cfa88dc16fd8c9bcc0c7f0b0073f7ef1e27cceb246c9f5a3f7004fa97c4d"},
{file = "rapidfuzz-2.15.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:509c5b631cd64df69f0f011893983eb15b8be087a55bad72f3d616b6ae6a0f96"},
{file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0f73a04135a03a6e40393ecd5d46a7a1049d353fc5c24b82849830d09817991f"},
{file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c99d53138a2dfe8ada67cb2855719f934af2733d726fbf73247844ce4dd6dd5"},
{file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f01fa757f0fb332a1f045168d29b0d005de6c39ee5ce5d6c51f2563bb53c601b"},
{file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60368e1add6e550faae65614844c43f8a96e37bf99404643b648bf2dba92c0fb"},
{file = "rapidfuzz-2.15.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:785744f1270828cc632c5a3660409dee9bcaac6931a081bae57542c93e4d46c4"},
{file = "rapidfuzz-2.15.1.tar.gz", hash = "sha256:d62137c2ca37aea90a11003ad7dc109c8f1739bfbe5a9a217f3cdb07d7ac00f6"},
]
[package.extras]
full = ["numpy"]
[[package]]
name = "textwrap3"
version = "0.9.2"
description = "textwrap from Python 3.6 backport (plus a few tweaks)"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "textwrap3-0.9.2-py2.py3-none-any.whl", hash = "sha256:bf5f4c40faf2a9ff00a9e0791fed5da7415481054cef45bb4a3cfb1f69044ae0"},
{file = "textwrap3-0.9.2.zip", hash = "sha256:5008eeebdb236f6303dcd68f18b856d355f6197511d952ba74bc75e40e0c3414"},
]
[[package]]
name = "watchdog"
version = "2.3.1"
description = "Filesystem events monitoring"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1f1200d4ec53b88bf04ab636f9133cb703eb19768a39351cee649de21a33697"},
{file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:564e7739abd4bd348aeafbf71cc006b6c0ccda3160c7053c4a53b67d14091d42"},
{file = "watchdog-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95ad708a9454050a46f741ba5e2f3468655ea22da1114e4c40b8cbdaca572565"},
{file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a073c91a6ef0dda488087669586768195c3080c66866144880f03445ca23ef16"},
{file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa8b028750b43e80eea9946d01925168eeadb488dfdef1d82be4b1e28067f375"},
{file = "watchdog-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:964fd236cd443933268ae49b59706569c8b741073dbfd7ca705492bae9d39aab"},
{file = "watchdog-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:91fd146d723392b3e6eb1ac21f122fcce149a194a2ba0a82c5e4d0ee29cd954c"},
{file = "watchdog-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f"},
{file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85bf2263290591b7c5fa01140601b64c831be88084de41efbcba6ea289874f44"},
{file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f2df370cd8e4e18499dd0bfdef476431bcc396108b97195d9448d90924e3131"},
{file = "watchdog-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b"},
{file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f5d0f7eac86807275eba40b577c671b306f6f335ba63a5c5a348da151aba0fc"},
{file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b848c71ef2b15d0ef02f69da8cc120d335cec0ed82a3fa7779e27a5a8527225"},
{file = "watchdog-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d9878be36d2b9271e3abaa6f4f051b363ff54dbbe7e7df1af3c920e4311ee43"},
{file = "watchdog-2.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cd61f98cb37143206818cb1786d2438626aa78d682a8f2ecee239055a9771d5"},
{file = "watchdog-2.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d2dbcf1acd96e7a9c9aefed201c47c8e311075105d94ce5e899f118155709fd"},
{file = "watchdog-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03f342a9432fe08107defbe8e405a2cb922c5d00c4c6c168c68b633c64ce6190"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7a596f9415a378d0339681efc08d2249e48975daae391d58f2e22a3673b977cf"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:0e1dd6d449267cc7d6935d7fe27ee0426af6ee16578eed93bacb1be9ff824d2d"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_i686.whl", hash = "sha256:7a1876f660e32027a1a46f8a0fa5747ad4fcf86cb451860eae61a26e102c8c79"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:2caf77ae137935c1466f8cefd4a3aec7017b6969f425d086e6a528241cba7256"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:53f3e95081280898d9e4fc51c5c69017715929e4eea1ab45801d5e903dd518ad"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:9da7acb9af7e4a272089bd2af0171d23e0d6271385c51d4d9bde91fe918c53ed"},
{file = "watchdog-2.3.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8a4d484e846dcd75e96b96d80d80445302621be40e293bfdf34a631cab3b33dc"},
{file = "watchdog-2.3.1-py3-none-win32.whl", hash = "sha256:a74155398434937ac2780fd257c045954de5b11b5c52fc844e2199ce3eecf4cf"},
{file = "watchdog-2.3.1-py3-none-win_amd64.whl", hash = "sha256:5defe4f0918a2a1a4afbe4dbb967f743ac3a93d546ea4674567806375b024adb"},
{file = "watchdog-2.3.1-py3-none-win_ia64.whl", hash = "sha256:4109cccf214b7e3462e8403ab1e5b17b302ecce6c103eb2fc3afa534a7f27b96"},
{file = "watchdog-2.3.1.tar.gz", hash = "sha256:d9f9ed26ed22a9d331820a8432c3680707ea8b54121ddcc9dc7d9f2ceeb36906"},
]
[package.extras]
watchmedo = ["PyYAML (>=3.10)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.7"
content-hash = "f48df5c526c5e9e9b6c8dd83bb06b628c347f616a66670800e3032a83ba50c08"

189
tools/asm-differ/test.py Normal file
View File

@ -0,0 +1,189 @@
import unittest
import diff
import json
class TestSh2(unittest.TestCase):
def get_config(self) -> diff.Config:
arch = diff.get_arch("sh2")
formatter = diff.JsonFormatter(arch_str="sh2")
config = diff.Config(
arch=arch,
diff_obj=True,
file='',
make=False,
source_old_binutils=True,
diff_section='.text',
inlines=False,
max_function_size_lines=25000,
max_function_size_bytes=100000,
formatter=formatter,
diff_mode=diff.DiffMode.NORMAL,
base_shift=0,
skip_lines=0,
compress=None,
show_rodata_refs=True,
show_branches=True,
show_line_numbers=False,
show_source=False,
stop_at_ret=None,
ignore_large_imms=False,
ignore_addr_diffs=True,
algorithm="levenshtein",
reg_categories={},
)
return config
# check that comment <> regex has ? to avoid "<func_060E8780+0x44>,r1 ! 60e87d0"
# all being a comment for:
# mov.l 44 <func_060E8780+0x44>,r1 ! 60e87d0
def test_sh2_comment(self) -> None:
# parser specifically looks for tabs so make sure they are represented
# 16: d1 0b mov.l 44 <func_060E8780+0x44>,r1 ! 60e87d0
sh2_theirs = (
" 16:\td1 0b \tmov.l\t44 <func_060E8780+0x44>,r1\t! 60e87d0\n"
)
# 16: d1 0b mov.l 44 <_func_060E8780+0x44>,r1 ! 0 <_func_060E8780>
sh2_ours = " 16:\td1 0b \tmov.l\t44 <_func_060E8780+0x44>,r1\t! 0 <_func_060E8780>\n"
config = self.get_config()
display = diff.Display(sh2_theirs, sh2_ours, config)
loaded = json.loads(display.run_diff()[0])
curr = loaded["rows"][0]["current"]["src_comment"]
assert curr != "<_func_060E8780+0x44>,r1 ! 0 <_func_060E8780>"
assert curr == "<_func_060E8780+0x44>"
def test_sh2_immediates(self) -> None:
# test parsing these immediates
# func_0606B760():
# 0: ec 01 mov #1,r12
# 2: 71 01 add #1,r1
# 4: ec ff mov #-1,r12
# 6: 71 ff add #-1,r1
# 8: ec 7f mov #127,r12
# a: 71 7f add #127,r1
# c: ec 80 mov #-128,r12
# e: 71 80 add #-128,r1
sh2_theirs = "func_0606B760():\n 0:\tec 01 \tmov\t#1,r12\n 2:\t71 01 \tadd\t#1,r1\n 4:\tec ff \tmov\t#-1,r12\n 6:\t71 ff \tadd\t#-1,r1\n 8:\tec 7f \tmov\t#127,r12\n a:\t71 7f \tadd\t#127,r1\n c:\tec 80 \tmov\t#-128,r12\n e:\t71 80 \tadd\t#-128,r1"
# just diff with self
sh2_ours = sh2_theirs
config = self.get_config()
display = diff.Display(sh2_theirs, sh2_ours, config)
loaded = json.loads(display.run_diff()[0])
expected = [
"0: mov #0x1,r12",
"2: add #0x1,r1",
"4: mov #0xff,r12",
"6: add #0xff,r1",
"8: mov #0x7f,r12",
"a: add #0x7f,r1",
"c: mov #0x80,r12",
"e: add #0x80,r1",
]
i = 0
for text in loaded["rows"]:
assert text["base"]["text"][0]["text"] == expected[i]
i += 1
def test_more_sh2_immediates(self) -> None:
# test that the re_int regex is able to catch all these "boundary" numbers
# since we have to match 0-9 one digit at a time
# 0: 71 00 add #0,r1
# 2: 71 01 add #1,r1
# 4: 71 09 add #9,r1
# 6: 71 0a add #10,r1
# 8: 71 0b add #11,r1
# a: 71 13 add #19,r1
# c: 71 64 add #100,r1
# e: 71 65 add #101,r1
# 10: 71 6d add #109,r1
# 12: 71 6f add #111,r1
# 14: 71 77 add #119,r1
# 16: 71 f7 add #-9,r1
# 18: 71 f6 add #-10,r1
# 1a: 71 f5 add #-11,r1
# 1c: 71 ed add #-19,r1
# 1e: 71 9c add #-100,r1
# 20: 71 9b add #-101,r1
# 22: 71 93 add #-109,r1
# 24: 71 91 add #-111,r1
# 26: 71 89 add #-119,r1
sh2_theirs = "func_0606B760():\n 0:\t71 00 \tadd\t#0,r1\n 2:\t71 01 \tadd\t#1,r1\n 4:\t71 09 \tadd\t#9,r1\n 6:\t71 0a \tadd\t#10,r1\n 8:\t71 0b \tadd\t#11,r1\n a:\t71 13 \tadd\t#19,r1\n c:\t71 64 \tadd\t#100,r1\n e:\t71 65 \tadd\t#101,r1\n 10:\t71 6d \tadd\t#109,r1\n 12:\t71 6f \tadd\t#111,r1\n 14:\t71 77 \tadd\t#119,r1\n 16:\t71 f7 \tadd\t#-9,r1\n 18:\t71 f6 \tadd\t#-10,r1\n 1a:\t71 f5 \tadd\t#-11,r1\n 1c:\t71 ed \tadd\t#-19,r1\n 1e:\t71 9c \tadd\t#-100,r1\n 20:\t71 9b \tadd\t#-101,r1\n 22:\t71 93 \tadd\t#-109,r1\n 24:\t71 91 \tadd\t#-111,r1\n 26:\t71 89 \tadd\t#-119,r1"
# just diff with self
sh2_ours = sh2_theirs
config = self.get_config()
display = diff.Display(sh2_theirs, sh2_ours, config)
loaded = json.loads(display.run_diff()[0])
expected = [
"0: add #0x0,r1",
"2: add #0x1,r1",
"4: add #0x9,r1",
"6: add #0xa,r1",
"8: add #0xb,r1",
"a: add #0x13,r1",
"c: add #0x64,r1",
"e: add #0x65,r1",
"10: add #0x6d,r1",
"12: add #0x6f,r1",
"14: add #0x77,r1",
"16: add #0xf7,r1",
"18: add #0xf6,r1",
"1a: add #0xf5,r1",
"1c: add #0xed,r1",
"1e: add #0x9c,r1",
"20: add #0x9b,r1",
"22: add #0x93,r1",
"24: add #0x91,r1",
"26: add #0x89,r1",
]
i = 0
for text in loaded["rows"]:
assert text["base"]["text"][0]["text"] == expected[i]
i += 1
def test_branch(self) -> None:
# test that bt.s and bra get ~>
# func():
# 0: 8d 02 bt.s 8 <lab_0606B780>
# 2: 6e f3 mov r15,r14
# 4: a0 01 bra a <lab_0606B8E0>
# 6: 00 09 nop
# 00000008 <lab_0606B780>:
# lab_0606B780():
# 8: db 32 mov.l d4 <lab_0606B8E0+0xca>,r11
# 0000000a <lab_0606B8E0>:
# lab_0606B8E0():
# a: 00 0b rts
# c: 00 09 nop
sh2_theirs = "func():\n 0:\t8d 02 \tbt.s\t8 <lab_0606B780>\n 2:\t6e f3 \tmov\tr15,r14\n 4:\ta0 01 \tbra\ta <lab_0606B8E0>\n 6:\t00 09 \tnop\t\n\n00000008 <lab_0606B780>:\nlab_0606B780():\n 8:\tdb 32 \tmov.l\td4 <lab_0606B8E0+0xca>,r11\n\n0000000a <lab_0606B8E0>:\nlab_0606B8E0():\n a:\t00 0b \trts\t\n c:\t00 09 \tnop\t"
sh2_ours = sh2_theirs
config = self.get_config()
display = diff.Display(sh2_theirs, sh2_ours, config)
loaded = json.loads(display.run_diff()[0])
# bt.s 8
print(loaded["rows"][0]["base"]["text"][1]["text"] == "~>")
print(loaded["rows"][0]["base"]["text"][1]["key"] == "8")
# bra a
print(loaded["rows"][2]["base"]["text"][1]["text"] == "~>")
print(loaded["rows"][2]["base"]["text"][1]["key"] == "10")
if __name__ == "__main__":
unittest.main()

View File

@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = git@github.com:simonlindholm/asm-processor.git remote = git@github.com:simonlindholm/asm-processor.git
branch = main branch = main
commit = bbd86ea1faf84e6a7a0e101ab8068a00a3dfb2fc commit = fed1e3ddb9967bd427f4599b1b8ededa296bd9f9
parent = 8985197b6da23db874ac6e8a29ddec5636944bba parent = 4fa13e4132cf8adb2f07bb34927e62e525c8cc79
method = merge method = merge
cmdver = 0.4.3 cmdver = 0.4.6

View File

@ -2,7 +2,6 @@
import argparse import argparse
import tempfile import tempfile
import struct import struct
import copy
import sys import sys
import re import re
import os import os
@ -82,7 +81,14 @@ R_MIPS_HI16 = 5
R_MIPS_LO16 = 6 R_MIPS_LO16 = 6
MIPS_DEBUG_ST_STATIC = 2 MIPS_DEBUG_ST_STATIC = 2
MIPS_DEBUG_ST_PROC = 6
MIPS_DEBUG_ST_BLOCK = 7
MIPS_DEBUG_ST_END = 8
MIPS_DEBUG_ST_FILE = 11
MIPS_DEBUG_ST_STATIC_PROC = 14 MIPS_DEBUG_ST_STATIC_PROC = 14
MIPS_DEBUG_ST_STRUCT = 26
MIPS_DEBUG_ST_UNION = 27
MIPS_DEBUG_ST_ENUM = 28
class ElfFormat: class ElfFormat:
@ -605,11 +611,11 @@ class GlobalAsmBlock:
line = re.sub(r'^[a-zA-Z0-9_]+:\s*', '', line) line = re.sub(r'^[a-zA-Z0-9_]+:\s*', '', line)
changed_section = False changed_section = False
emitting_double = False emitting_double = False
if line.startswith('glabel ') and self.cur_section == '.text': if (line.startswith('glabel ') or line.startswith('jlabel ')) and self.cur_section == '.text':
self.text_glabels.append(line.split()[1]) self.text_glabels.append(line.split()[1])
if not line: if not line:
pass # empty line pass # empty line
elif line.startswith('glabel ') or line.startswith('dlabel ') or line.startswith('endlabel ') or (' ' not in line and line.endswith(':')): elif line.startswith('glabel ') or line.startswith('dlabel ') or line.startswith('jlabel ') or line.startswith('endlabel ') or (' ' not in line and line.endswith(':')):
pass # label pass # label
elif line.startswith('.section') or line in ['.text', '.data', '.rdata', '.rodata', '.bss', '.late_rodata']: elif line.startswith('.section') or line in ['.text', '.data', '.rdata', '.rodata', '.bss', '.late_rodata']:
# section change # section change
@ -651,19 +657,26 @@ class GlobalAsmBlock:
emitting_double = True emitting_double = True
elif line.startswith('.space'): elif line.startswith('.space'):
self.add_sized(int(line.split()[1], 0), real_line) self.add_sized(int(line.split()[1], 0), real_line)
elif line.startswith('.balign') or line.startswith('.align'): elif line.startswith('.balign'):
align = int(line.split()[1]) align = int(line.split()[1])
if align != 4: if align != 4:
self.fail("only .balign 4 is supported", real_line) self.fail("only .balign 4 is supported", real_line)
self.align4() self.align4()
elif line.startswith('.align'):
align = int(line.split()[1])
if align != 2:
self.fail("only .align 2 is supported", real_line)
self.align4()
elif line.startswith('.asci'): elif line.startswith('.asci'):
z = (line.startswith('.asciz') or line.startswith('.asciiz')) z = (line.startswith('.asciz') or line.startswith('.asciiz'))
self.add_sized(self.count_quoted_size(line, z, real_line, output_enc), real_line) self.add_sized(self.count_quoted_size(line, z, real_line, output_enc), real_line)
elif line.startswith('.byte'): elif line.startswith('.byte'):
self.add_sized(len(line.split(',')), real_line) self.add_sized(len(line.split(',')), real_line)
elif line.startswith('.half'): elif line.startswith('.half') or line.startswith('.hword') or line.startswith(".short"):
self.align2() self.align2()
self.add_sized(2*len(line.split(',')), real_line) self.add_sized(2*len(line.split(',')), real_line)
elif line.startswith('.size'):
pass
elif line.startswith('.'): elif line.startswith('.'):
# .macro, ... # .macro, ...
self.fail("asm directive not supported", real_line) self.fail("asm directive not supported", real_line)
@ -1268,6 +1281,7 @@ def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc, d
# Add static symbols from .mdebug, so they can be referred to from GLOBAL_ASM # Add static symbols from .mdebug, so they can be referred to from GLOBAL_ASM
if mdebug_section and convert_statics != "no": if mdebug_section and convert_statics != "no":
static_name_count = {}
strtab_index = len(objfile.symtab.strtab.data) strtab_index = len(objfile.symtab.strtab.data)
new_strtab_data = [] new_strtab_data = []
ifd_max, cb_fd_offset = fmt.unpack('II', mdebug_section.data[18*4 : 20*4]) ifd_max, cb_fd_offset = fmt.unpack('II', mdebug_section.data[18*4 : 20*4])
@ -1276,20 +1290,28 @@ def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc, d
for i in range(ifd_max): for i in range(ifd_max):
offset = cb_fd_offset + 18*4*i offset = cb_fd_offset + 18*4*i
iss_base, _, isym_base, csym = fmt.unpack('IIII', objfile.data[offset + 2*4 : offset + 6*4]) iss_base, _, isym_base, csym = fmt.unpack('IIII', objfile.data[offset + 2*4 : offset + 6*4])
scope_level = 0
for j in range(csym): for j in range(csym):
offset2 = cb_sym_offset + 12 * (isym_base + j) offset2 = cb_sym_offset + 12 * (isym_base + j)
iss, value, st_sc_index = fmt.unpack('III', objfile.data[offset2 : offset2 + 12]) iss, value, st_sc_index = fmt.unpack('III', objfile.data[offset2 : offset2 + 12])
st = (st_sc_index >> 26) st = (st_sc_index >> 26)
sc = (st_sc_index >> 21) & 0x1f sc = (st_sc_index >> 21) & 0x1f
if st in [MIPS_DEBUG_ST_STATIC, MIPS_DEBUG_ST_STATIC_PROC]: if st in (MIPS_DEBUG_ST_STATIC, MIPS_DEBUG_ST_STATIC_PROC):
symbol_name_offset = cb_ss_offset + iss_base + iss symbol_name_offset = cb_ss_offset + iss_base + iss
symbol_name_offset_end = objfile.data.find(b'\0', symbol_name_offset) symbol_name_offset_end = objfile.data.find(b'\0', symbol_name_offset)
assert symbol_name_offset_end != -1 assert symbol_name_offset_end != -1
symbol_name = objfile.data[symbol_name_offset : symbol_name_offset_end + 1] symbol_name = objfile.data[symbol_name_offset : symbol_name_offset_end]
if scope_level > 1:
# For in-function statics, append an increasing counter to
# the name, to avoid duplicate conflicting symbols.
count = static_name_count.get(symbol_name, 0) + 1
static_name_count[symbol_name] = count
symbol_name += b":" + str(count).encode("utf-8")
emitted_symbol_name = symbol_name emitted_symbol_name = symbol_name
if convert_statics == "global-with-filename": if convert_statics == "global-with-filename":
# Change the emitted symbol name to include the filename, # Change the emitted symbol name to include the filename,
# but don't let that affect deduplication logic. # but don't let that affect deduplication logic (we still
# want to be able to reference statics from GLOBAL_ASM).
emitted_symbol_name = objfile_name.encode("utf-8") + b":" + symbol_name emitted_symbol_name = objfile_name.encode("utf-8") + b":" + symbol_name
section_name = {1: '.text', 2: '.data', 3: '.bss', 15: '.rodata'}[sc] section_name = {1: '.text', 2: '.data', 3: '.bss', 15: '.rodata'}[sc]
section = objfile.find_section(section_name) section = objfile.find_section(section_name)
@ -1304,10 +1326,23 @@ def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc, d
st_other=STV_DEFAULT, st_other=STV_DEFAULT,
st_shndx=section.index, st_shndx=section.index,
strtab=objfile.symtab.strtab, strtab=objfile.symtab.strtab,
name=symbol_name[:-1].decode('latin1')) name=symbol_name.decode('latin1'))
strtab_index += len(emitted_symbol_name) strtab_index += len(emitted_symbol_name) + 1
new_strtab_data.append(emitted_symbol_name) new_strtab_data.append(emitted_symbol_name + b'\0')
new_syms.append(sym) new_syms.append(sym)
if st in (
MIPS_DEBUG_ST_FILE,
MIPS_DEBUG_ST_STRUCT,
MIPS_DEBUG_ST_UNION,
MIPS_DEBUG_ST_ENUM,
MIPS_DEBUG_ST_BLOCK,
MIPS_DEBUG_ST_PROC,
MIPS_DEBUG_ST_STATIC_PROC,
):
scope_level += 1
if st == MIPS_DEBUG_ST_END:
scope_level -= 1
assert scope_level == 0
objfile.symtab.strtab.data += b''.join(new_strtab_data) objfile.symtab.strtab.data += b''.join(new_strtab_data)
# Get rid of duplicate symbols, favoring ones that are not UNDEF. # Get rid of duplicate symbols, favoring ones that are not UNDEF.

View File

@ -0,0 +1,3 @@
[mypy]
files = asm_processor.py, build.py

View File

@ -1,11 +1,21 @@
.set noat .set noat
.set noreorder .set noreorder
.set gp=64 .set gp=64
.macro glabel label .macro glabel label
.global \label .global \label
\label: \label:
.endm .endm
.macro dlabel label
.global \label
\label:
.endm
.macro jlabel label
\label:
.endm
# Float register aliases (o32 ABI, odd ones are rarely used) # Float register aliases (o32 ABI, odd ones are rarely used)

View File

@ -25,9 +25,11 @@ nop
) )
static int xtext(int a, int b, int c) { static int xtext(int a, int b, int c) {
static int bss2;
return 1; return 1;
} }
void baz(void) { void baz(void) {
{ static int bss2; }
xtext(bss2, rodata2[0], data2[0]); xtext(bss2, rodata2[0], data2[0]);
} }

View File

@ -15,6 +15,8 @@ SYMBOL TABLE:
00000004 g O .data 00000000 data2 00000004 g O .data 00000000 data2
00000004 g O .bss 00000000 bss2 00000004 g O .bss 00000000 bss2
00000030 g F .text 00000000 xtext 00000030 g F .text 00000000 xtext
00000008 g O .bss 00000000 bss2:1
0000000c g O .bss 00000000 bss2:2
RELOCATION RECORDS FOR [.text]: RELOCATION RECORDS FOR [.text]:

View File

@ -6,7 +6,7 @@
[subrepo] [subrepo]
remote = git@github.com:EllipticEllipsis/fado.git remote = git@github.com:EllipticEllipsis/fado.git
branch = master branch = master
commit = 8d896ee97d565508755584803c409fc33bb0c953 commit = 8ce0483766e2857c6f2997880ab7a5381b2cc5c3
parent = b51c9f4d22d6e7db63700c163418654431a2a61a parent = aa8be27d62d8485c61f88889faf6132e4f66590b
method = merge method = merge
cmdver = 0.4.3 cmdver = 0.4.6

View File

@ -57,7 +57,7 @@ clean:
$(RM) -r build $(ELF) $(RM) -r build $(ELF)
format: format:
clang-format-11 -i $(C_FILES) $(H_FILES) lib/fairy/* clang-format-14 -i $(C_FILES) $(H_FILES) lib/fairy/*
.PHONY: all clean format .PHONY: all clean format

View File

@ -476,9 +476,9 @@ typedef struct {
/* Relocation table entry with addend (in section of type SHT_RELA). */ /* Relocation table entry with addend (in section of type SHT_RELA). */
typedef struct { typedef struct {
Elf32_Addr r_offset; /* Address */ Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */ Elf32_Word r_info; /* Relocation type and symbol index */
Elf32_Sword r_addend; /* Addend */ Elf32_Sword r_addend; /* Addend */
} Elf32_Rela; } Elf32_Rela;
/* How to extract and insert information held in the r_info field. */ /* How to extract and insert information held in the r_info field. */