From a2b8ab1205e873252f03afe656d6340b33fad942 Mon Sep 17 00:00:00 2001 From: Lil-Ran Date: Wed, 5 Mar 2025 22:55:46 +0800 Subject: [PATCH] sync with dc5d2b9 --- .gitignore | 3 ++ ASTree.cpp | 114 +++++++++++++++++++++++++++++++++++++++++++------ CMakeLists.txt | 8 +--- pyc_code.cpp | 4 +- pycdas.cpp | 49 +++++++++++++++------ pycdc.cpp | 2 + 6 files changed, 145 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 7cfe02d..5f2729a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ /.kdev4 __pycache__ tests-out + +.vscode/ +build/ diff --git a/ASTree.cpp b/ASTree.cpp index 1f419d0..dc77f31 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -607,6 +607,32 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(call); } break; + // BEGIN ONESHOT TEMPORARY PATCH + case Pyc::CALL_FUNCTION_EX_A: + { + PycRef kw; + if (operand & 0x01) + { + kw = stack.top(); + stack.pop(); + } + PycRef var = stack.top(); + stack.pop(); + PycRef func = stack.top(); + stack.pop(); + if (stack.top() == nullptr) + { + stack.pop(); + } + + PycRef call = new ASTCall(func, ASTCall::pparam_t(), ASTCall::kwparam_t()); + if (operand & 0x01) + call.cast()->setKW(kw); + call.cast()->setVar(var); + stack.push(call); + } + break; + // END ONESHOT PATCH case Pyc::CALL_METHOD_A: { ASTCall::pparam_t pparamList; @@ -1307,6 +1333,19 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) bool push = true; do { + // BEGIN ONESHOT TEMPORARY PATCH + // This implementation is probably wrong + // Skip junk code on top level scope + auto &top = blocks.top(); + if (top == defblock) { + pos += offs; + for (int i = 0; i < offs; i++) { + source.getByte(); + } + break; + } + // END ONESHOT PATCH + blocks.pop(); if (!blocks.empty()) @@ -1374,7 +1413,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) blocks.push(except); } } else { - fprintf(stderr, "Something TERRIBLE happened!!\n"); + fprintf(stderr, "Something TERRIBLE happened!! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); } prev = nil; } else { @@ -1606,7 +1646,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack = stack_hist.top(); stack_hist.pop(); } else { - fprintf(stderr, "Warning: Stack history is empty, something wrong might have happened\n"); + fprintf(stderr, "Warning: Stack history is empty, something wrong might have happened at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); } } PycRef tmp = curblock; @@ -1890,7 +1931,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.pop(); if (none != NULL) { - fprintf(stderr, "Something TERRIBLE happened!\n"); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); break; } @@ -1998,7 +2040,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) if (tup.type() == ASTNode::NODE_TUPLE) tup.cast()->add(attr); else - fputs("Something TERRIBLE happened!\n", stderr); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); if (--unpack <= 0) { stack.pop(); @@ -2033,7 +2076,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) if (tup.type() == ASTNode::NODE_TUPLE) tup.cast()->add(name); else - fputs("Something TERRIBLE happened!\n", stderr); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); if (--unpack <= 0) { stack.pop(); @@ -2073,7 +2117,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) if (tup.type() == ASTNode::NODE_TUPLE) tup.cast()->add(name); else - fputs("Something TERRIBLE happened!\n", stderr); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); if (--unpack <= 0) { stack.pop(); @@ -2132,7 +2177,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) if (tup.type() == ASTNode::NODE_TUPLE) tup.cast()->add(name); else - fputs("Something TERRIBLE happened!\n", stderr); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); if (--unpack <= 0) { stack.pop(); @@ -2174,7 +2220,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) if (tup.type() == ASTNode::NODE_TUPLE) tup.cast()->add(name); else - fputs("Something TERRIBLE happened!\n", stderr); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); if (--unpack <= 0) { stack.pop(); @@ -2295,7 +2342,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) if (tup.type() == ASTNode::NODE_TUPLE) tup.cast()->add(save); else - fputs("Something TERRIBLE happened!\n", stderr); + fprintf(stderr, "Something TERRIBLE happened! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); if (--unpack <= 0) { stack.pop(); @@ -2473,8 +2521,42 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) stack.push(next_tup); } break; + // BEGIN ONESHOT TEMPORARY PATCH + // These opcodes are not implemented + case Pyc::COPY_A: + { + FastStack tmp_stack(20); + for (int i = 0; i < operand - 1; i++) { + tmp_stack.push(stack.top()); + stack.pop(); + } + auto value = stack.top(); + for (int i = 0; i < operand - 1; i++) { + stack.push(tmp_stack.top()); + tmp_stack.pop(); + } + stack.push(value); + } + case Pyc::PUSH_EXC_INFO: + { + stack.push(stack.top()); + } + case Pyc::JUMP_IF_NOT_EXC_MATCH_A: + { + PycRef ex_type = stack.top(); + stack.pop(); + PycRef cur_ex = stack.top(); + stack.pop(); + } + case Pyc::RERAISE: + case Pyc::RERAISE_A: + break; + // END ONESHOT PATCH default: - fprintf(stderr, "Unsupported opcode: %s (%d)\n", Pyc::OpcodeName(opcode), opcode); + fprintf(stderr, "Unsupported opcode: %s (%d) at %s\n", + Pyc::OpcodeName(opcode), + opcode, + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); cleanBuild = false; return new ASTNodeList(defblock->nodes()); } @@ -2486,7 +2568,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } if (stack_hist.size()) { - fputs("Warning: Stack history is not empty!\n", stderr); + fprintf(stderr, "Warning: Stack history is not empty! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); while (stack_hist.size()) { stack_hist.pop(); @@ -2494,7 +2577,8 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) } if (blocks.size() > 1) { - fputs("Warning: block stack is not empty!\n", stderr); + fprintf(stderr, "Warning: block stack is not empty! at %s\n", + mod->verCompare(3, 11) >= 0 ? code->qualName()->value() : code->name()->value()); while (blocks.size() > 1) { PycRef tmp = blocks.top(); @@ -2898,6 +2982,12 @@ void print_src(PycRef node, PycModule* mod, std::ostream& pyc_output) case ASTNode::NODE_BLOCK: { PycRef blk = node.cast(); + + // BEGIN ONESHOT TEMPORARY PATCH + if (blk->blktype() == ASTBlock::BLK_MAIN) + break; + // END ONESHOT PATCH + if (blk->blktype() == ASTBlock::BLK_ELSE && blk->size() == 0) break; diff --git a/CMakeLists.txt b/CMakeLists.txt index 476c964..6e0d828 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,13 +64,7 @@ add_library(pycxx STATIC bytes/python_3_13.cpp ) -add_executable(pycdas pycdas.cpp) -target_link_libraries(pycdas pycxx) - -install(TARGETS pycdas - RUNTIME DESTINATION bin) - -add_executable(pycdc pycdc.cpp ASTree.cpp ASTNode.cpp) +add_executable(pycdc pycdas.cpp ASTree.cpp ASTNode.cpp) target_link_libraries(pycdc pycxx) install(TARGETS pycdc diff --git a/pyc_code.cpp b/pyc_code.cpp index ba63eed..e080bb2 100644 --- a/pyc_code.cpp +++ b/pyc_code.cpp @@ -67,8 +67,8 @@ void PycCode::load(PycData* stream, PycModule* mod) if (mod->verCompare(3, 8) < 0) { // Remap flags to new values introduced in 3.8 if (m_flags & 0xF0000000) - throw std::runtime_error("Cannot remap unexpected flags"); - m_flags = (m_flags & 0xFFFF) | ((m_flags & 0xFFF0000) << 4); + fprintf(stderr, "Remapping flags (%08X) may not be correct\n", m_flags); + m_flags = (m_flags & 0x1FFF) | ((m_flags & 0xFFFE000) << 4); } m_code = LoadObject(stream, mod).cast(); diff --git a/pycdas.cpp b/pycdas.cpp index b73410f..664bd5c 100644 --- a/pycdas.cpp +++ b/pycdas.cpp @@ -7,6 +7,7 @@ #include "pyc_module.h" #include "pyc_numeric.h" #include "bytecode.h" +#include "ASTree.h" #ifdef WIN32 # define PATHSEP '\\' @@ -104,7 +105,7 @@ void output_object(PycRef obj, PycModule* mod, int indent, unsigned int orig_flags = codeObj->flags(); if (mod->verCompare(3, 8) < 0) { // Remap flags back to the value stored in the PyCode object - orig_flags = (orig_flags & 0xFFFF) | ((orig_flags & 0xFFF00000) >> 4); + orig_flags = (orig_flags & 0x1FFF) | ((orig_flags & 0xFFFE0000) >> 4); } iprintf(pyc_output, indent + 1, "Flags: 0x%08X", orig_flags); print_coflags(codeObj->flags(), pyc_output); @@ -251,23 +252,17 @@ void output_object(PycRef obj, PycModule* mod, int indent, int main(int argc, char* argv[]) { const char* infile = nullptr; + const char* outfile = nullptr; bool marshalled = false; const char* version = nullptr; unsigned disasm_flags = 0; - std::ostream* pyc_output = &std::cout; - std::ofstream out_file; + std::ofstream dc_out_file; + std::ofstream das_out_file; for (int arg = 1; arg < argc; ++arg) { if (strcmp(argv[arg], "-o") == 0) { if (arg + 1 < argc) { - const char* filename = argv[++arg]; - out_file.open(filename, std::ios_base::out); - if (out_file.fail()) { - fprintf(stderr, "Error opening file '%s' for writing\n", - filename); - return 1; - } - pyc_output = &out_file; + outfile = argv[++arg]; } else { fputs("Option '-o' requires a filename\n", stderr); return 1; @@ -288,7 +283,7 @@ int main(int argc, char* argv[]) } else if (strcmp(argv[arg], "--help") == 0 || strcmp(argv[arg], "-h") == 0) { fprintf(stderr, "Usage: %s [options] input.pyc\n\n", argv[0]); fputs("Options:\n", stderr); - fputs(" -o Write output to (default: stdout)\n", stderr); + fputs(" -o Write output to .das and .cdc.py\n", stderr); fputs(" -c Specify loading a compiled code object. Requires the version to be set\n", stderr); fputs(" -v Specify a Python version for loading a compiled code object\n", stderr); fputs(" --pycode-extra Show extra fields in PyCode object dumps\n", stderr); @@ -308,6 +303,20 @@ int main(int argc, char* argv[]) return 1; } + std::string prefix_name(outfile ? outfile : infile); + + dc_out_file.open(prefix_name + ".cdc.py", std::ios_base::out); + if (dc_out_file.fail()) { + fprintf(stderr, "Error opening file '%s' for writing\n", (prefix_name + ".cdc.py").c_str()); + return 1; + } + + das_out_file.open(prefix_name + ".das", std::ios_base::out); + if (das_out_file.fail()) { + fprintf(stderr, "Error opening file '%s' for writing\n", (prefix_name + ".das").c_str()); + return 1; + } + PycModule mod; if (!marshalled) { try { @@ -333,16 +342,28 @@ int main(int argc, char* argv[]) } const char* dispname = strrchr(infile, PATHSEP); dispname = (dispname == NULL) ? infile : dispname + 1; - formatted_print(*pyc_output, "%s (Python %d.%d%s)\n", dispname, + + formatted_print(das_out_file, "%s (Python %d.%d%s)\n", dispname, mod.majorVer(), mod.minorVer(), (mod.majorVer() < 3 && mod.isUnicode()) ? " -U" : ""); try { output_object(mod.code().try_cast(), &mod, 0, disasm_flags, - *pyc_output); + das_out_file); } catch (std::exception& ex) { fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what()); return 1; } + dc_out_file << "# Source Generated with Decompyle++\n"; + formatted_print(dc_out_file, "# File: %s (Python %d.%d%s)\n\n", dispname, + mod.majorVer(), mod.minorVer(), + (mod.majorVer() < 3 && mod.isUnicode()) ? " Unicode" : ""); + try { + decompyle(mod.code(), &mod, dc_out_file); + } catch (std::exception& ex) { + fprintf(stderr, "Error decompyling %s: %s\n", infile, ex.what()); + return 1; + } + return 0; } diff --git a/pycdc.cpp b/pycdc.cpp index 7bb6bd2..3ce000d 100644 --- a/pycdc.cpp +++ b/pycdc.cpp @@ -1,3 +1,5 @@ +// THIS FILE IS UNUSED FOR ONESHOT FORK + #include #include #include