Compare commits
17 Commits
master
...
5e70e1e084
| Author | SHA1 | Date | |
|---|---|---|---|
|
5e70e1e084
|
|||
|
1c413c5124
|
|||
|
49557e7580
|
|||
|
6c6aa159df
|
|||
|
b5983f505f
|
|||
|
7a0044914c
|
|||
|
3359b0e1b2
|
|||
|
8b8fe3020a
|
|||
|
|
1d1237228a | ||
|
|
97e49d644f | ||
|
db5f282e61
|
|||
|
299a59f0a9
|
|||
|
45ea5f4ac8
|
|||
|
33f2cc57c0
|
|||
|
e4f96df166
|
|||
|
93c9e47e82
|
|||
|
a2b8ab1205
|
46
.github/workflows/build.yml
vendored
Normal file
46
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches: [fork]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake --build . --config Debug
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pycdc-fork-${{ matrix.os }}
|
||||
path: build/pycdc
|
||||
|
||||
windows-build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "MinGW Makefiles" ..
|
||||
cmake --build . --config Debug
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pycdc-fork-windows
|
||||
path: build/pycdc.exe
|
||||
67
.github/workflows/codeql-analysis.yml
vendored
67
.github/workflows/codeql-analysis.yml
vendored
@@ -1,67 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 1 * * 2'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['cpp', 'python']
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- if: matrix.language == 'python'
|
||||
name: Autobuild Python
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- if: matrix.language == 'cpp'
|
||||
name: Build C++
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
|
||||
make
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
29
.github/workflows/linux-ci.yml
vendored
29
.github/workflows/linux-ci.yml
vendored
@@ -1,29 +0,0 @@
|
||||
name: Linux-CI
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Configure and Build
|
||||
run: |
|
||||
(
|
||||
mkdir build-debug && cd build-debug
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make -j4
|
||||
)
|
||||
|
||||
(
|
||||
mkdir build-release && cd build-release
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make -j4
|
||||
)
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cmake --build build-debug --target check
|
||||
cmake --build build-release --target check
|
||||
29
.github/workflows/msvc-ci.yml
vendored
29
.github/workflows/msvc-ci.yml
vendored
@@ -1,29 +0,0 @@
|
||||
name: MSVC-CI
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Configure and Build
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 17 2022" -A Win32 ..
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config Release
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cmake --build build --config Debug --target check
|
||||
cmake --build build --config Release --target check
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pycdc-release
|
||||
path: build\Release\*.exe
|
||||
229
ASTree.cpp
229
ASTree.cpp
@@ -424,6 +424,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
}
|
||||
break;
|
||||
case Pyc::CALL_A:
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
case Pyc::CALL_KW_A:
|
||||
// END ONESHOT PATCH
|
||||
case Pyc::CALL_FUNCTION_A:
|
||||
case Pyc::INSTRUMENTED_CALL_A:
|
||||
{
|
||||
@@ -455,6 +458,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
stack.pop();
|
||||
PycRef<ASTNode> loadbuild = stack.top();
|
||||
stack.pop();
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
if (loadbuild == nullptr)
|
||||
{
|
||||
loadbuild = stack.top();
|
||||
stack.pop();
|
||||
}
|
||||
if (stack.top() == nullptr)
|
||||
{
|
||||
stack.pop();
|
||||
}
|
||||
// END ONESHOT PATCH
|
||||
int loadbuild_type = loadbuild.type();
|
||||
if (loadbuild_type == ASTNode::NODE_LOADBUILDCLASS) {
|
||||
PycRef<ASTNode> call = new ASTCall(function, pparamList, kwparamList);
|
||||
@@ -468,13 +482,19 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
stack_hist.pop();
|
||||
}
|
||||
|
||||
/*
|
||||
KW_NAMES(i)
|
||||
Stores a reference to co_consts[consti] into an internal variable for use by CALL.
|
||||
co_consts[consti] must be a tuple of strings.
|
||||
New in version 3.11.
|
||||
*/
|
||||
if (mod->verCompare(3, 11) >= 0) {
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
if (mod->verCompare(3, 13) >= 0 && opcode == Pyc::CALL_KW_A) {
|
||||
PycRef<PycTuple> kw_names = stack.top().cast<ASTObject>()->object().cast<PycTuple>();
|
||||
stack.pop();
|
||||
kwparams = kw_names->values().size();
|
||||
pparams = operand - kwparams;
|
||||
for (auto it = kw_names->values().rbegin(); it != kw_names->values().rend(); it++) {
|
||||
kwparamList.push_front(std::make_pair(new ASTObject(*it), stack.top()));
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
else if (mod->verCompare(3, 11) >= 0) {
|
||||
// END ONESHOT PATCH
|
||||
PycRef<ASTNode> object_or_map = stack.top();
|
||||
if (object_or_map.type() == ASTNode::NODE_KW_NAMES_MAP) {
|
||||
stack.pop();
|
||||
@@ -514,12 +534,22 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
pparamList.push_front(param);
|
||||
}
|
||||
}
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
// For Python 3.13 and later
|
||||
if (mod->verCompare(3, 13) >= 0) {
|
||||
PycRef<ASTNode> self_or_null = stack.top();
|
||||
stack.pop();
|
||||
if (self_or_null != nullptr) {
|
||||
pparamList.push_front(self_or_null);
|
||||
}
|
||||
}
|
||||
PycRef<ASTNode> func = stack.top();
|
||||
stack.pop();
|
||||
if ((opcode == Pyc::CALL_A || opcode == Pyc::INSTRUMENTED_CALL_A) &&
|
||||
stack.top() == nullptr) {
|
||||
mod->verCompare(3, 13) < 0 && stack.top() == nullptr) {
|
||||
stack.pop();
|
||||
}
|
||||
// END ONESHOT PATCH
|
||||
|
||||
stack.push(new ASTCall(func, pparamList, kwparamList));
|
||||
}
|
||||
@@ -608,6 +638,41 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
stack.push(call);
|
||||
}
|
||||
break;
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
case Pyc::CALL_FUNCTION_EX_A:
|
||||
{
|
||||
PycRef<ASTNode> kw;
|
||||
if (operand & 0x01)
|
||||
{
|
||||
kw = stack.top();
|
||||
stack.pop();
|
||||
}
|
||||
PycRef<ASTNode> var = stack.top();
|
||||
stack.pop();
|
||||
|
||||
ASTCall::pparam_t pparamList;
|
||||
if (mod->verCompare(3, 13) >= 0)
|
||||
{
|
||||
PycRef<ASTNode> param = stack.top();
|
||||
stack.pop();
|
||||
if (param != nullptr)
|
||||
pparamList.push_front(param);
|
||||
}
|
||||
PycRef<ASTNode> func = stack.top();
|
||||
stack.pop();
|
||||
if (mod->verCompare(3, 13) < 0 && stack.top() == nullptr)
|
||||
{
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
PycRef<ASTNode> call = new ASTCall(func, pparamList, ASTCall::kwparam_t());
|
||||
if (operand & 0x01)
|
||||
call.cast<ASTCall>()->setKW(kw);
|
||||
call.cast<ASTCall>()->setVar(var);
|
||||
stack.push(call);
|
||||
}
|
||||
break;
|
||||
// END ONESHOT PATCH
|
||||
case Pyc::CALL_METHOD_A:
|
||||
{
|
||||
ASTCall::pparam_t pparamList;
|
||||
@@ -1318,6 +1383,19 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> 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())
|
||||
@@ -1385,7 +1463,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> 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 {
|
||||
@@ -1561,6 +1640,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
break;
|
||||
case Pyc::MAKE_CLOSURE_A:
|
||||
case Pyc::MAKE_FUNCTION_A:
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
case Pyc::MAKE_FUNCTION:
|
||||
// END ONESHOT PATCH
|
||||
{
|
||||
PycRef<ASTNode> fun_code = stack.top();
|
||||
stack.pop();
|
||||
@@ -1574,19 +1656,49 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
}
|
||||
|
||||
ASTFunction::defarg_t defArgs, kwDefArgs;
|
||||
const int defCount = operand & 0xFF;
|
||||
const int kwDefCount = (operand >> 8) & 0xFF;
|
||||
for (int i = 0; i < defCount; ++i) {
|
||||
defArgs.push_front(stack.top());
|
||||
stack.pop();
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
if (mod->verCompare(3, 6) < 0)
|
||||
{
|
||||
const int defCount = operand & 0xFF;
|
||||
const int kwDefCount = (operand >> 8) & 0xFF;
|
||||
for (int i = 0; i < defCount; ++i) {
|
||||
defArgs.push_front(stack.top());
|
||||
stack.pop();
|
||||
}
|
||||
for (int i = 0; i < kwDefCount; ++i) {
|
||||
kwDefArgs.push_front(stack.top());
|
||||
stack.pop();
|
||||
}
|
||||
if ((operand >> 16) & 0x7FFF) {
|
||||
// a tuple listing the parameter names for the annotations (only if there are any annotation objects)
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < kwDefCount; ++i) {
|
||||
kwDefArgs.push_front(stack.top());
|
||||
stack.pop();
|
||||
else if (mod->verCompare(3, 13) < 0)
|
||||
{
|
||||
if (operand & 0x08)
|
||||
stack.pop();
|
||||
if (operand & 0x04)
|
||||
stack.pop();
|
||||
if (operand & 0x02)
|
||||
stack.pop();
|
||||
if (operand & 0x01)
|
||||
stack.pop();
|
||||
}
|
||||
// END ONESHOT PATCH
|
||||
stack.push(new ASTFunction(fun_code, defArgs, kwDefArgs));
|
||||
}
|
||||
break;
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
case Pyc::SET_FUNCTION_ATTRIBUTE_A:
|
||||
{
|
||||
PycRef<ASTNode> func = stack.top();
|
||||
stack.pop();
|
||||
stack.pop();
|
||||
stack.push(func);
|
||||
}
|
||||
break;
|
||||
// END ONESHOT PATCH
|
||||
case Pyc::NOP:
|
||||
break;
|
||||
case Pyc::POP_BLOCK:
|
||||
@@ -1617,9 +1729,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> 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());
|
||||
}
|
||||
}
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
// The problem is not here, but in the way the blocks are created
|
||||
// Add this to avoid segfault
|
||||
if (blocks.top() == defblock)
|
||||
break;
|
||||
// END ONESHOT PATCH
|
||||
|
||||
PycRef<ASTBlock> tmp = curblock;
|
||||
blocks.pop();
|
||||
|
||||
@@ -1849,7 +1969,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
curblock = blocks.top();
|
||||
curblock->append(prev.cast<ASTNode>());
|
||||
|
||||
bc_next(source, mod, opcode, operand, pos);
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
// bc_next(source, mod, opcode, operand, pos);
|
||||
// END ONESHOT PATCH
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1928,7 +2050,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> 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;
|
||||
}
|
||||
|
||||
@@ -2036,7 +2159,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||
tup.cast<ASTTuple>()->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();
|
||||
@@ -2071,7 +2195,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||
tup.cast<ASTTuple>()->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();
|
||||
@@ -2111,7 +2236,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||
tup.cast<ASTTuple>()->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();
|
||||
@@ -2170,7 +2296,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||
tup.cast<ASTTuple>()->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();
|
||||
@@ -2212,7 +2339,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||
tup.cast<ASTTuple>()->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();
|
||||
@@ -2333,7 +2461,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||
tup.cast<ASTTuple>()->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();
|
||||
@@ -2488,6 +2617,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
as no-ops. */
|
||||
break;
|
||||
case Pyc::PUSH_NULL:
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
case Pyc::BEGIN_FINALLY:
|
||||
// END ONESHOT PATCH
|
||||
stack.push(nullptr);
|
||||
break;
|
||||
case Pyc::GEN_START_A:
|
||||
@@ -2511,6 +2643,34 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
stack.push(next_tup);
|
||||
}
|
||||
break;
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
// THESE OPCODES ARE NOT IMPLEMENTED HERE
|
||||
case Pyc::PUSH_EXC_INFO:
|
||||
{
|
||||
stack.push(stack.top());
|
||||
}
|
||||
break;
|
||||
case Pyc::JUMP_IF_NOT_EXC_MATCH_A:
|
||||
{
|
||||
PycRef<ASTNode> ex_type = stack.top();
|
||||
stack.pop();
|
||||
PycRef<ASTNode> cur_ex = stack.top();
|
||||
stack.pop();
|
||||
}
|
||||
break;
|
||||
case Pyc::RERAISE:
|
||||
case Pyc::RERAISE_A:
|
||||
case Pyc::MAKE_CELL_A:
|
||||
case Pyc::COPY_FREE_VARS_A:
|
||||
case Pyc::TO_BOOL:
|
||||
case Pyc::CALL_INTRINSIC_1_A:
|
||||
break;
|
||||
case Pyc::CALL_INTRINSIC_2_A:
|
||||
{
|
||||
stack.pop();
|
||||
}
|
||||
break;
|
||||
// END ONESHOT PATCH
|
||||
case Pyc::BINARY_SLICE:
|
||||
{
|
||||
PycRef<ASTNode> end = stack.top();
|
||||
@@ -2585,7 +2745,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
}
|
||||
break;
|
||||
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());
|
||||
}
|
||||
@@ -2597,7 +2760,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> 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();
|
||||
@@ -2605,7 +2769,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> 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<ASTBlock> tmp = blocks.top();
|
||||
@@ -3017,6 +3182,12 @@ void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output)
|
||||
case ASTNode::NODE_BLOCK:
|
||||
{
|
||||
PycRef<ASTBlock> blk = node.cast<ASTBlock>();
|
||||
|
||||
// BEGIN ONESHOT TEMPORARY PATCH
|
||||
if (blk->blktype() == ASTBlock::BLK_MAIN)
|
||||
break;
|
||||
// END ONESHOT PATCH
|
||||
|
||||
if (blk->blktype() == ASTBlock::BLK_ELSE && blk->size() == 0)
|
||||
break;
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ elseif(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++ ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(pycxx STATIC
|
||||
@@ -62,15 +66,10 @@ add_library(pycxx STATIC
|
||||
bytes/python_3_11.cpp
|
||||
bytes/python_3_12.cpp
|
||||
bytes/python_3_13.cpp
|
||||
bytes/python_3_14.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
|
||||
|
||||
@@ -39,6 +39,7 @@ DECLARE_PYTHON(3, 10)
|
||||
DECLARE_PYTHON(3, 11)
|
||||
DECLARE_PYTHON(3, 12)
|
||||
DECLARE_PYTHON(3, 13)
|
||||
DECLARE_PYTHON(3, 14)
|
||||
|
||||
const char* Pyc::OpcodeName(int opcode)
|
||||
{
|
||||
@@ -109,6 +110,7 @@ int Pyc::ByteToOpcode(int maj, int min, int opcode)
|
||||
case 11: return python_3_11_map(opcode);
|
||||
case 12: return python_3_12_map(opcode);
|
||||
case 13: return python_3_13_map(opcode);
|
||||
case 14: return python_3_14_map(opcode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
102
bytecode_ops.inl
102
bytecode_ops.inl
@@ -124,6 +124,104 @@ OPCODE(FORMAT_WITH_SPEC) // Python 3.13 ->
|
||||
OPCODE(MAKE_FUNCTION) // Python 3.13 ->
|
||||
OPCODE(TO_BOOL) // Python 3.13 ->
|
||||
|
||||
OPCODE(BUILD_TEMPLATE) // Python 3.14 ->
|
||||
OPCODE(BINARY_OP_INPLACE_ADD_UNICODE)
|
||||
OPCODE(NOT_TAKEN)
|
||||
OPCODE(POP_ITER)
|
||||
OPCODE(BUILD_INTERPOLATION)
|
||||
OPCODE(LOAD_COMMON_CONSTANT)
|
||||
OPCODE(LOAD_FAST_BORROW)
|
||||
OPCODE(LOAD_FAST_BORROW_LOAD_FAST_BORROW)
|
||||
OPCODE(LOAD_SPECIAL)
|
||||
OPCODE(BINARY_OP_ADD_FLOAT)
|
||||
OPCODE(BINARY_OP_ADD_INT)
|
||||
OPCODE(BINARY_OP_ADD_UNICODE)
|
||||
OPCODE(BINARY_OP_EXTEND)
|
||||
OPCODE(BINARY_OP_MULTIPLY_FLOAT)
|
||||
OPCODE(BINARY_OP_MULTIPLY_INT)
|
||||
OPCODE(BINARY_OP_SUBSCR_DICT)
|
||||
OPCODE(BINARY_OP_SUBSCR_GETITEM)
|
||||
OPCODE(BINARY_OP_SUBSCR_LIST_INT)
|
||||
OPCODE(BINARY_OP_SUBSCR_LIST_SLICE)
|
||||
OPCODE(BINARY_OP_SUBSCR_STR_INT)
|
||||
OPCODE(BINARY_OP_SUBSCR_TUPLE_INT)
|
||||
OPCODE(BINARY_OP_SUBTRACT_FLOAT)
|
||||
OPCODE(BINARY_OP_SUBTRACT_INT)
|
||||
OPCODE(CALL_ALLOC_AND_ENTER_INIT)
|
||||
OPCODE(CALL_BOUND_METHOD_EXACT_ARGS)
|
||||
OPCODE(CALL_BOUND_METHOD_GENERAL)
|
||||
OPCODE(CALL_BUILTIN_CLASS)
|
||||
OPCODE(CALL_BUILTIN_FAST)
|
||||
OPCODE(CALL_BUILTIN_FAST_WITH_KEYWORDS)
|
||||
OPCODE(CALL_BUILTIN_O)
|
||||
OPCODE(CALL_ISINSTANCE)
|
||||
OPCODE(CALL_KW_BOUND_METHOD)
|
||||
OPCODE(CALL_KW_NON_PY)
|
||||
OPCODE(CALL_KW_PY)
|
||||
OPCODE(CALL_LEN)
|
||||
OPCODE(CALL_LIST_APPEND)
|
||||
OPCODE(CALL_METHOD_DESCRIPTOR_FAST)
|
||||
OPCODE(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS)
|
||||
OPCODE(CALL_METHOD_DESCRIPTOR_NOARGS)
|
||||
OPCODE(CALL_METHOD_DESCRIPTOR_O)
|
||||
OPCODE(CALL_NON_PY_GENERAL)
|
||||
OPCODE(CALL_PY_EXACT_ARGS)
|
||||
OPCODE(CALL_PY_GENERAL)
|
||||
OPCODE(CALL_STR_1)
|
||||
OPCODE(CALL_TUPLE_1)
|
||||
OPCODE(CALL_TYPE_1)
|
||||
OPCODE(COMPARE_OP_FLOAT)
|
||||
OPCODE(COMPARE_OP_INT)
|
||||
OPCODE(COMPARE_OP_STR)
|
||||
OPCODE(CONTAINS_OP_DICT)
|
||||
OPCODE(CONTAINS_OP_SET)
|
||||
OPCODE(FOR_ITER_GEN)
|
||||
OPCODE(FOR_ITER_LIST)
|
||||
OPCODE(FOR_ITER_RANGE)
|
||||
OPCODE(FOR_ITER_TUPLE)
|
||||
OPCODE(JUMP_BACKWARD_JIT)
|
||||
OPCODE(JUMP_BACKWARD_NO_JIT)
|
||||
OPCODE(LOAD_ATTR_CLASS)
|
||||
OPCODE(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK)
|
||||
OPCODE(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN)
|
||||
OPCODE(LOAD_ATTR_INSTANCE_VALUE)
|
||||
OPCODE(LOAD_ATTR_METHOD_LAZY_DICT)
|
||||
OPCODE(LOAD_ATTR_METHOD_NO_DICT)
|
||||
OPCODE(LOAD_ATTR_METHOD_WITH_VALUES)
|
||||
OPCODE(LOAD_ATTR_MODULE)
|
||||
OPCODE(LOAD_ATTR_NONDESCRIPTOR_NO_DICT)
|
||||
OPCODE(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES)
|
||||
OPCODE(LOAD_ATTR_PROPERTY)
|
||||
OPCODE(LOAD_ATTR_SLOT)
|
||||
OPCODE(LOAD_ATTR_WITH_HINT)
|
||||
OPCODE(LOAD_CONST_IMMORTAL)
|
||||
OPCODE(LOAD_CONST_MORTAL)
|
||||
OPCODE(LOAD_GLOBAL_BUILTIN)
|
||||
OPCODE(LOAD_GLOBAL_MODULE)
|
||||
OPCODE(LOAD_SUPER_ATTR_ATTR)
|
||||
OPCODE(LOAD_SUPER_ATTR_METHOD)
|
||||
OPCODE(RESUME_CHECK)
|
||||
OPCODE(SEND_GEN)
|
||||
OPCODE(STORE_ATTR_INSTANCE_VALUE)
|
||||
OPCODE(STORE_ATTR_SLOT)
|
||||
OPCODE(STORE_ATTR_WITH_HINT)
|
||||
OPCODE(STORE_SUBSCR_DICT)
|
||||
OPCODE(STORE_SUBSCR_LIST_INT)
|
||||
OPCODE(TO_BOOL_ALWAYS_TRUE)
|
||||
OPCODE(TO_BOOL_BOOL)
|
||||
OPCODE(TO_BOOL_INT)
|
||||
OPCODE(TO_BOOL_LIST)
|
||||
OPCODE(TO_BOOL_NONE)
|
||||
OPCODE(TO_BOOL_STR)
|
||||
OPCODE(UNPACK_SEQUENCE_LIST)
|
||||
OPCODE(UNPACK_SEQUENCE_TUPLE)
|
||||
OPCODE(UNPACK_SEQUENCE_TWO_TUPLE)
|
||||
OPCODE(ANNOTATIONS_PLACEHOLDER)
|
||||
OPCODE(JUMP)
|
||||
OPCODE(JUMP_NO_INTERRUPT)
|
||||
OPCODE(SETUP_CLEANUP)
|
||||
OPCODE(STORE_FAST_MAYBE_NULL)
|
||||
|
||||
/* Has parameter word */
|
||||
OPCODE_A_FIRST(STORE_NAME) // Python 1.0 -> names[A]
|
||||
OPCODE_A(DELETE_NAME) // Python 1.0 -> names[A]
|
||||
@@ -269,6 +367,7 @@ OPCODE_A(LOAD_FAST_LOAD_FAST) // Python 3.13 -> A=locals
|
||||
OPCODE_A(SET_FUNCTION_ATTRIBUTE) // Python 3.13 -> A=attribute_type
|
||||
OPCODE_A(STORE_FAST_LOAD_FAST) // Python 3.13 -> A=locals[A<<4]+locals[A&0xf]
|
||||
OPCODE_A(STORE_FAST_STORE_FAST) // Python 3.13 -> A=locals[A<<4]+locals[A&0xf]
|
||||
OPCODE_A(LOAD_SMALL_INT) // Python 3.14 -> A=small int range(256)
|
||||
|
||||
/* Instrumented opcodes */
|
||||
OPCODE_A(INSTRUMENTED_LOAD_SUPER_ATTR) // Python 3.12 -> (see LOAD_SUPER_ATTR)
|
||||
@@ -290,3 +389,6 @@ OPCODE_A(INSTRUMENTED_END_SEND) // Python 3.12 -> (see END
|
||||
OPCODE_A(INSTRUMENTED_INSTRUCTION) // Python 3.12 -> A=(unused)
|
||||
OPCODE_A(INSTRUMENTED_LINE) // Python 3.12 -> ???
|
||||
OPCODE_A(INSTRUMENTED_CALL_KW) // Python 3.13 -> (see CALL_KW)
|
||||
OPCODE_A(INSTRUMENTED_POP_ITER) // Python 3.14 -> (see POP_ITER)
|
||||
OPCODE_A(INSTRUMENTED_NOT_TAKEN) // Python 3.14 -> (see NOT_TAKEN)
|
||||
OPCODE_A(INSTRUMENTED_END_ASYNC_FOR) // Python 3.14 -> (see END_ASYNC_FOR)
|
||||
|
||||
242
bytes/python_3_14.cpp
Normal file
242
bytes/python_3_14.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
#include "bytecode_map.h"
|
||||
|
||||
BEGIN_MAP(3, 14)
|
||||
MAP_OP(0, CACHE)
|
||||
MAP_OP(1, BINARY_SLICE)
|
||||
MAP_OP(2, BUILD_TEMPLATE)
|
||||
MAP_OP(3, BINARY_OP_INPLACE_ADD_UNICODE)
|
||||
MAP_OP(4, CALL_FUNCTION_EX_A)
|
||||
MAP_OP(5, CHECK_EG_MATCH)
|
||||
MAP_OP(6, CHECK_EXC_MATCH)
|
||||
MAP_OP(7, CLEANUP_THROW)
|
||||
MAP_OP(8, DELETE_SUBSCR)
|
||||
MAP_OP(9, END_FOR)
|
||||
MAP_OP(10, END_SEND)
|
||||
MAP_OP(11, EXIT_INIT_CHECK)
|
||||
MAP_OP(12, FORMAT_SIMPLE)
|
||||
MAP_OP(13, FORMAT_WITH_SPEC)
|
||||
MAP_OP(14, GET_AITER)
|
||||
MAP_OP(15, GET_ANEXT)
|
||||
MAP_OP(16, GET_ITER)
|
||||
MAP_OP(17, RESERVED)
|
||||
MAP_OP(18, GET_LEN)
|
||||
MAP_OP(19, GET_YIELD_FROM_ITER)
|
||||
MAP_OP(20, INTERPRETER_EXIT)
|
||||
MAP_OP(21, LOAD_BUILD_CLASS)
|
||||
MAP_OP(22, LOAD_LOCALS)
|
||||
MAP_OP(23, MAKE_FUNCTION)
|
||||
MAP_OP(24, MATCH_KEYS)
|
||||
MAP_OP(25, MATCH_MAPPING)
|
||||
MAP_OP(26, MATCH_SEQUENCE)
|
||||
MAP_OP(27, NOP)
|
||||
MAP_OP(28, NOT_TAKEN)
|
||||
MAP_OP(29, POP_EXCEPT)
|
||||
MAP_OP(30, POP_ITER)
|
||||
MAP_OP(31, POP_TOP)
|
||||
MAP_OP(32, PUSH_EXC_INFO)
|
||||
MAP_OP(33, PUSH_NULL)
|
||||
MAP_OP(34, RETURN_GENERATOR)
|
||||
MAP_OP(35, RETURN_VALUE)
|
||||
MAP_OP(36, SETUP_ANNOTATIONS)
|
||||
MAP_OP(37, STORE_SLICE)
|
||||
MAP_OP(38, STORE_SUBSCR)
|
||||
MAP_OP(39, TO_BOOL)
|
||||
MAP_OP(40, UNARY_INVERT)
|
||||
MAP_OP(41, UNARY_NEGATIVE)
|
||||
MAP_OP(42, UNARY_NOT)
|
||||
MAP_OP(43, WITH_EXCEPT_START)
|
||||
MAP_OP(44, BINARY_OP_A)
|
||||
MAP_OP(45, BUILD_INTERPOLATION)
|
||||
MAP_OP(46, BUILD_LIST_A)
|
||||
MAP_OP(47, BUILD_MAP_A)
|
||||
MAP_OP(48, BUILD_SET_A)
|
||||
MAP_OP(49, BUILD_SLICE_A)
|
||||
MAP_OP(50, BUILD_STRING_A)
|
||||
MAP_OP(51, BUILD_TUPLE_A)
|
||||
MAP_OP(52, CALL_A)
|
||||
MAP_OP(53, CALL_INTRINSIC_1_A)
|
||||
MAP_OP(54, CALL_INTRINSIC_2_A)
|
||||
MAP_OP(55, CALL_KW_A)
|
||||
MAP_OP(56, COMPARE_OP_A)
|
||||
MAP_OP(57, CONTAINS_OP_A)
|
||||
MAP_OP(58, CONVERT_VALUE_A)
|
||||
MAP_OP(59, COPY_A)
|
||||
MAP_OP(60, COPY_FREE_VARS_A)
|
||||
MAP_OP(61, DELETE_ATTR_A)
|
||||
MAP_OP(62, DELETE_DEREF_A)
|
||||
MAP_OP(63, DELETE_FAST_A)
|
||||
MAP_OP(64, DELETE_GLOBAL_A)
|
||||
MAP_OP(65, DELETE_NAME_A)
|
||||
MAP_OP(66, DICT_MERGE_A)
|
||||
MAP_OP(67, DICT_UPDATE_A)
|
||||
MAP_OP(68, END_ASYNC_FOR)
|
||||
MAP_OP(69, EXTENDED_ARG_A)
|
||||
MAP_OP(70, FOR_ITER_A)
|
||||
MAP_OP(71, GET_AWAITABLE_A)
|
||||
MAP_OP(72, IMPORT_FROM_A)
|
||||
MAP_OP(73, IMPORT_NAME_A)
|
||||
MAP_OP(74, IS_OP_A)
|
||||
MAP_OP(75, JUMP_BACKWARD_A)
|
||||
MAP_OP(76, JUMP_BACKWARD_NO_INTERRUPT_A)
|
||||
MAP_OP(77, JUMP_FORWARD_A)
|
||||
MAP_OP(78, LIST_APPEND)
|
||||
MAP_OP(79, LIST_EXTEND_A)
|
||||
MAP_OP(80, LOAD_ATTR_A)
|
||||
MAP_OP(81, LOAD_COMMON_CONSTANT)
|
||||
MAP_OP(82, LOAD_CONST_A)
|
||||
MAP_OP(83, LOAD_DEREF_A)
|
||||
MAP_OP(84, LOAD_FAST_A)
|
||||
MAP_OP(85, LOAD_FAST_AND_CLEAR_A)
|
||||
MAP_OP(86, LOAD_FAST_BORROW)
|
||||
MAP_OP(87, LOAD_FAST_BORROW_LOAD_FAST_BORROW)
|
||||
MAP_OP(88, LOAD_FAST_CHECK_A)
|
||||
MAP_OP(89, LOAD_FAST_LOAD_FAST_A)
|
||||
MAP_OP(90, LOAD_FROM_DICT_OR_DEREF_A)
|
||||
MAP_OP(91, LOAD_FROM_DICT_OR_GLOBALS_A)
|
||||
MAP_OP(92, LOAD_GLOBAL_A)
|
||||
MAP_OP(93, LOAD_NAME_A)
|
||||
MAP_OP(94, LOAD_SMALL_INT_A)
|
||||
MAP_OP(95, LOAD_SPECIAL)
|
||||
MAP_OP(96, LOAD_SUPER_ATTR_A)
|
||||
MAP_OP(97, MAKE_CELL_A)
|
||||
MAP_OP(98, MAP_ADD_A)
|
||||
MAP_OP(99, MATCH_CLASS_A)
|
||||
MAP_OP(100, POP_JUMP_IF_FALSE_A)
|
||||
MAP_OP(101, POP_JUMP_IF_NONE_A)
|
||||
MAP_OP(102, POP_JUMP_IF_NOT_NONE_A)
|
||||
MAP_OP(103, POP_JUMP_IF_TRUE_A)
|
||||
MAP_OP(104, RAISE_VARARGS_A)
|
||||
MAP_OP(105, RERAISE)
|
||||
MAP_OP(106, SEND_A)
|
||||
MAP_OP(107, SET_ADD)
|
||||
MAP_OP(108, SET_FUNCTION_ATTRIBUTE_A)
|
||||
MAP_OP(109, SET_UPDATE_A)
|
||||
MAP_OP(110, STORE_ATTR_A)
|
||||
MAP_OP(111, STORE_DEREF_A)
|
||||
MAP_OP(112, STORE_FAST_A)
|
||||
MAP_OP(113, STORE_FAST_LOAD_FAST_A)
|
||||
MAP_OP(114, STORE_FAST_STORE_FAST_A)
|
||||
MAP_OP(115, STORE_GLOBAL_A)
|
||||
MAP_OP(116, STORE_NAME_A)
|
||||
MAP_OP(117, SWAP_A)
|
||||
MAP_OP(118, UNPACK_EX_A)
|
||||
MAP_OP(119, UNPACK_SEQUENCE_A)
|
||||
MAP_OP(120, YIELD_VALUE_A)
|
||||
MAP_OP(128, RESUME_A)
|
||||
MAP_OP(129, BINARY_OP_ADD_FLOAT)
|
||||
MAP_OP(130, BINARY_OP_ADD_INT)
|
||||
MAP_OP(131, BINARY_OP_ADD_UNICODE)
|
||||
MAP_OP(132, BINARY_OP_EXTEND)
|
||||
MAP_OP(133, BINARY_OP_MULTIPLY_FLOAT)
|
||||
MAP_OP(134, BINARY_OP_MULTIPLY_INT)
|
||||
MAP_OP(135, BINARY_OP_SUBSCR_DICT)
|
||||
MAP_OP(136, BINARY_OP_SUBSCR_GETITEM)
|
||||
MAP_OP(137, BINARY_OP_SUBSCR_LIST_INT)
|
||||
MAP_OP(138, BINARY_OP_SUBSCR_LIST_SLICE)
|
||||
MAP_OP(139, BINARY_OP_SUBSCR_STR_INT)
|
||||
MAP_OP(140, BINARY_OP_SUBSCR_TUPLE_INT)
|
||||
MAP_OP(141, BINARY_OP_SUBTRACT_FLOAT)
|
||||
MAP_OP(142, BINARY_OP_SUBTRACT_INT)
|
||||
MAP_OP(143, CALL_ALLOC_AND_ENTER_INIT)
|
||||
MAP_OP(144, CALL_BOUND_METHOD_EXACT_ARGS)
|
||||
MAP_OP(145, CALL_BOUND_METHOD_GENERAL)
|
||||
MAP_OP(146, CALL_BUILTIN_CLASS)
|
||||
MAP_OP(147, CALL_BUILTIN_FAST)
|
||||
MAP_OP(148, CALL_BUILTIN_FAST_WITH_KEYWORDS)
|
||||
MAP_OP(149, CALL_BUILTIN_O)
|
||||
MAP_OP(150, CALL_ISINSTANCE)
|
||||
MAP_OP(151, CALL_KW_BOUND_METHOD)
|
||||
MAP_OP(152, CALL_KW_NON_PY)
|
||||
MAP_OP(153, CALL_KW_PY)
|
||||
MAP_OP(154, CALL_LEN)
|
||||
MAP_OP(155, CALL_LIST_APPEND)
|
||||
MAP_OP(156, CALL_METHOD_DESCRIPTOR_FAST)
|
||||
MAP_OP(157, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS)
|
||||
MAP_OP(158, CALL_METHOD_DESCRIPTOR_NOARGS)
|
||||
MAP_OP(159, CALL_METHOD_DESCRIPTOR_O)
|
||||
MAP_OP(160, CALL_NON_PY_GENERAL)
|
||||
MAP_OP(161, CALL_PY_EXACT_ARGS)
|
||||
MAP_OP(162, CALL_PY_GENERAL)
|
||||
MAP_OP(163, CALL_STR_1)
|
||||
MAP_OP(164, CALL_TUPLE_1)
|
||||
MAP_OP(165, CALL_TYPE_1)
|
||||
MAP_OP(166, COMPARE_OP_FLOAT)
|
||||
MAP_OP(167, COMPARE_OP_INT)
|
||||
MAP_OP(168, COMPARE_OP_STR)
|
||||
MAP_OP(169, CONTAINS_OP_DICT)
|
||||
MAP_OP(170, CONTAINS_OP_SET)
|
||||
MAP_OP(171, FOR_ITER_GEN)
|
||||
MAP_OP(172, FOR_ITER_LIST)
|
||||
MAP_OP(173, FOR_ITER_RANGE)
|
||||
MAP_OP(174, FOR_ITER_TUPLE)
|
||||
MAP_OP(175, JUMP_BACKWARD_JIT)
|
||||
MAP_OP(176, JUMP_BACKWARD_NO_JIT)
|
||||
MAP_OP(177, LOAD_ATTR_CLASS)
|
||||
MAP_OP(178, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK)
|
||||
MAP_OP(179, LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN)
|
||||
MAP_OP(180, LOAD_ATTR_INSTANCE_VALUE)
|
||||
MAP_OP(181, LOAD_ATTR_METHOD_LAZY_DICT)
|
||||
MAP_OP(182, LOAD_ATTR_METHOD_NO_DICT)
|
||||
MAP_OP(183, LOAD_ATTR_METHOD_WITH_VALUES)
|
||||
MAP_OP(184, LOAD_ATTR_MODULE)
|
||||
MAP_OP(185, LOAD_ATTR_NONDESCRIPTOR_NO_DICT)
|
||||
MAP_OP(186, LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES)
|
||||
MAP_OP(187, LOAD_ATTR_PROPERTY)
|
||||
MAP_OP(188, LOAD_ATTR_SLOT)
|
||||
MAP_OP(189, LOAD_ATTR_WITH_HINT)
|
||||
MAP_OP(190, LOAD_CONST_IMMORTAL)
|
||||
MAP_OP(191, LOAD_CONST_MORTAL)
|
||||
MAP_OP(192, LOAD_GLOBAL_BUILTIN)
|
||||
MAP_OP(193, LOAD_GLOBAL_MODULE)
|
||||
MAP_OP(194, LOAD_SUPER_ATTR_ATTR)
|
||||
MAP_OP(195, LOAD_SUPER_ATTR_METHOD)
|
||||
MAP_OP(196, RESUME_CHECK)
|
||||
MAP_OP(197, SEND_GEN)
|
||||
MAP_OP(198, STORE_ATTR_INSTANCE_VALUE)
|
||||
MAP_OP(199, STORE_ATTR_SLOT)
|
||||
MAP_OP(200, STORE_ATTR_WITH_HINT)
|
||||
MAP_OP(201, STORE_SUBSCR_DICT)
|
||||
MAP_OP(202, STORE_SUBSCR_LIST_INT)
|
||||
MAP_OP(203, TO_BOOL_ALWAYS_TRUE)
|
||||
MAP_OP(204, TO_BOOL_BOOL)
|
||||
MAP_OP(205, TO_BOOL_INT)
|
||||
MAP_OP(206, TO_BOOL_LIST)
|
||||
MAP_OP(207, TO_BOOL_NONE)
|
||||
MAP_OP(208, TO_BOOL_STR)
|
||||
MAP_OP(209, UNPACK_SEQUENCE_LIST)
|
||||
MAP_OP(210, UNPACK_SEQUENCE_TUPLE)
|
||||
MAP_OP(211, UNPACK_SEQUENCE_TWO_TUPLE)
|
||||
MAP_OP(234, INSTRUMENTED_END_FOR_A)
|
||||
MAP_OP(235, INSTRUMENTED_POP_ITER_A)
|
||||
MAP_OP(236, INSTRUMENTED_END_SEND_A)
|
||||
MAP_OP(237, INSTRUMENTED_FOR_ITER_A)
|
||||
MAP_OP(238, INSTRUMENTED_INSTRUCTION_A)
|
||||
MAP_OP(239, INSTRUMENTED_JUMP_FORWARD_A)
|
||||
MAP_OP(240, INSTRUMENTED_NOT_TAKEN_A)
|
||||
MAP_OP(241, INSTRUMENTED_POP_JUMP_IF_TRUE_A)
|
||||
MAP_OP(242, INSTRUMENTED_POP_JUMP_IF_FALSE_A)
|
||||
MAP_OP(243, INSTRUMENTED_POP_JUMP_IF_NONE_A)
|
||||
MAP_OP(244, INSTRUMENTED_POP_JUMP_IF_NOT_NONE_A)
|
||||
MAP_OP(245, INSTRUMENTED_RESUME_A)
|
||||
MAP_OP(246, INSTRUMENTED_RETURN_VALUE_A)
|
||||
MAP_OP(247, INSTRUMENTED_YIELD_VALUE_A)
|
||||
MAP_OP(248, INSTRUMENTED_END_ASYNC_FOR_A)
|
||||
MAP_OP(249, INSTRUMENTED_LOAD_SUPER_ATTR_A)
|
||||
MAP_OP(250, INSTRUMENTED_CALL_A)
|
||||
MAP_OP(251, INSTRUMENTED_CALL_KW_A)
|
||||
MAP_OP(252, INSTRUMENTED_CALL_FUNCTION_EX_A)
|
||||
MAP_OP(253, INSTRUMENTED_JUMP_BACKWARD_A)
|
||||
MAP_OP(254, INSTRUMENTED_LINE_A)
|
||||
MAP_OP(255, ENTER_EXECUTOR_A)
|
||||
MAP_OP(256, ANNOTATIONS_PLACEHOLDER)
|
||||
MAP_OP(257, JUMP)
|
||||
MAP_OP(258, JUMP_IF_FALSE_A)
|
||||
MAP_OP(259, JUMP_IF_TRUE_A)
|
||||
MAP_OP(260, JUMP_NO_INTERRUPT)
|
||||
MAP_OP(261, LOAD_CLOSURE_A)
|
||||
MAP_OP(262, POP_BLOCK)
|
||||
MAP_OP(263, SETUP_CLEANUP)
|
||||
MAP_OP(264, SETUP_FINALLY_A)
|
||||
MAP_OP(265, SETUP_WITH_A)
|
||||
MAP_OP(266, STORE_FAST_MAYBE_NULL)
|
||||
END_MAP()
|
||||
@@ -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<PycString>();
|
||||
|
||||
@@ -182,6 +182,12 @@ void PycModule::setVersion(unsigned int magic)
|
||||
m_unicode = true;
|
||||
break;
|
||||
|
||||
case MAGIC_3_14:
|
||||
m_maj = 3;
|
||||
m_min = 14;
|
||||
m_unicode = true;
|
||||
break;
|
||||
|
||||
/* Bad Magic detected */
|
||||
default:
|
||||
m_maj = -1;
|
||||
@@ -197,7 +203,7 @@ bool PycModule::isSupportedVersion(int major, int minor)
|
||||
case 2:
|
||||
return (minor >= 0 && minor <= 7);
|
||||
case 3:
|
||||
return (minor >= 0 && minor <= 12);
|
||||
return (minor >= 0 && minor <= 14);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ enum PycMagic {
|
||||
MAGIC_3_11 = 0x0A0D0DA7,
|
||||
MAGIC_3_12 = 0x0A0D0DCB,
|
||||
MAGIC_3_13 = 0x0A0D0DF3,
|
||||
MAGIC_3_14 = 0x0A0D0E2B,
|
||||
|
||||
INVALID = 0,
|
||||
};
|
||||
|
||||
183
pycdas.cpp
183
pycdas.cpp
@@ -1,3 +1,19 @@
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cstdarg>
|
||||
@@ -8,6 +24,7 @@
|
||||
#include "pyc_module.h"
|
||||
#include "pyc_numeric.h"
|
||||
#include "bytecode.h"
|
||||
#include "ASTree.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# define PATHSEP '\\'
|
||||
@@ -15,6 +32,68 @@
|
||||
# define PATHSEP '/'
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Windows: Use SEH/UEF; prefer calling only Win32 APIs
|
||||
#ifdef __cpp_lib_fstream_native_handle
|
||||
static HANDLE g_dc_h = INVALID_HANDLE_VALUE;
|
||||
static HANDLE g_das_h = INVALID_HANDLE_VALUE;
|
||||
#endif
|
||||
|
||||
static LONG WINAPI av_handler(EXCEPTION_POINTERS* /*ep*/) {
|
||||
const char msg[] = "Access violation caught. Best-effort FlushFileBuffers.\n";
|
||||
DWORD wrote = 0;
|
||||
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, sizeof(msg) - 1, &wrote, nullptr);
|
||||
#ifdef __cpp_lib_fstream_native_handle
|
||||
if (g_das_h != INVALID_HANDLE_VALUE) FlushFileBuffers(g_das_h);
|
||||
if (g_dc_h != INVALID_HANDLE_VALUE) FlushFileBuffers(g_dc_h);
|
||||
#endif
|
||||
TerminateProcess(GetCurrentProcess(), 0xC0000005);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
struct SehInstall {
|
||||
SehInstall() {
|
||||
// Suppress WER popups; let the UEF handle it directly
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
|
||||
SetUnhandledExceptionFilter(av_handler);
|
||||
}
|
||||
} seh_install_guard;
|
||||
|
||||
#else // !_WIN32
|
||||
|
||||
#ifdef __cpp_lib_fstream_native_handle
|
||||
static int g_dc_fd = -1;
|
||||
static int g_das_fd = -1;
|
||||
|
||||
static void segv_handler(int sig) {
|
||||
const char msg[] = "Access violation caught. Best-effort fsync.\n";
|
||||
// Only use async-signal-safe functions
|
||||
write(STDERR_FILENO, msg, sizeof(msg)-1);
|
||||
if (g_das_fd != -1) fsync(g_das_fd);
|
||||
if (g_dc_fd != -1) fsync(g_dc_fd);
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
#else
|
||||
static void segv_handler(int sig) {
|
||||
const char msg[] = "Access violation caught.\n";
|
||||
write(STDERR_FILENO, msg, sizeof(msg)-1);
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct SegvInstall {
|
||||
SegvInstall() {
|
||||
struct sigaction sa{};
|
||||
sa.sa_handler = segv_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGSEGV, &sa, nullptr);
|
||||
}
|
||||
} segv_install_guard;
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
static const char* flag_names[] = {
|
||||
"CO_OPTIMIZED", "CO_NEWLOCALS", "CO_VARARGS", "CO_VARKEYWORDS",
|
||||
"CO_NESTED", "CO_GENERATOR", "CO_NOFREE", "CO_COROUTINE",
|
||||
@@ -113,7 +192,7 @@ void output_object(PycRef<PycObject> 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);
|
||||
@@ -261,24 +340,21 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
fputs("LilRan's fork of Pycdc, output will be written to <filename>.das and <filename>.cdc.py\n", stderr);
|
||||
|
||||
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;
|
||||
bool unitbuf = false;
|
||||
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;
|
||||
@@ -299,18 +375,25 @@ 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 <filename> Write output to <filename> (default: stdout)\n", stderr);
|
||||
fputs(" -o <filename> Write output to <filename>.das and <filename>.cdc.py\n", stderr);
|
||||
fputs(" -c Specify loading a compiled code object. Requires the version to be set\n", stderr);
|
||||
fputs(" -v <x.y> Specify a Python version for loading a compiled code object\n", stderr);
|
||||
fputs(" --pycode-extra Show extra fields in PyCode object dumps\n", stderr);
|
||||
fputs(" --show-caches Don't suprress CACHE instructions in Python 3.11+ disassembly\n", stderr);
|
||||
fputs(" --unitbuf Set output streams to be unbuffered\n", stderr);
|
||||
fputs(" --help Show this help text and then exit\n", stderr);
|
||||
return 0;
|
||||
} else if (strcmp(argv[arg], "--unitbuf") == 0) {
|
||||
unitbuf = true;
|
||||
} else if (argv[arg][0] == '-') {
|
||||
fprintf(stderr, "Error: Unrecognized argument %s\n", argv[arg]);
|
||||
return 1;
|
||||
} else {
|
||||
} else if (!infile) {
|
||||
infile = argv[arg];
|
||||
} else {
|
||||
fprintf(stderr, "Error: Only one input file allowed, got %s and %s\n",
|
||||
infile, argv[arg]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,6 +402,54 @@ 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 (unitbuf) {
|
||||
dc_out_file.setf(std::ios::unitbuf);
|
||||
}
|
||||
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 (unitbuf) {
|
||||
das_out_file.setf(std::ios::unitbuf);
|
||||
}
|
||||
if (das_out_file.fail()) {
|
||||
fprintf(stderr, "Error opening file '%s' for writing\n", (prefix_name + ".das").c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_fstream_native_handle
|
||||
#ifndef _WIN32
|
||||
g_dc_fd = dc_out_file.native_handle();
|
||||
g_das_fd = das_out_file.native_handle();
|
||||
#else
|
||||
// Extract underlying handles to flush on exceptions
|
||||
// MSVC's native_handle is typically a HANDLE; MinGW may return a fd, requiring conversion via _get_osfhandle
|
||||
auto dc_nh = dc_out_file.native_handle();
|
||||
auto das_nh = das_out_file.native_handle();
|
||||
using native_handle_t = decltype(dc_nh);
|
||||
if constexpr (std::is_same_v<native_handle_t, HANDLE>) {
|
||||
g_dc_h = dc_nh;
|
||||
g_das_h = das_nh;
|
||||
} else if constexpr (std::is_integral_v<native_handle_t>) {
|
||||
intptr_t dc_handle = _get_osfhandle(dc_nh);
|
||||
if (dc_handle != -1 && dc_handle != reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE)) {
|
||||
g_dc_h = reinterpret_cast<HANDLE>(dc_handle);
|
||||
}
|
||||
intptr_t das_handle = _get_osfhandle(das_nh);
|
||||
if (das_handle != -1 && das_handle != reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE)) {
|
||||
g_das_h = reinterpret_cast<HANDLE>(das_handle);
|
||||
}
|
||||
} else {
|
||||
// ignore, keep as INVALID_HANDLE_VALUE
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
PycModule mod;
|
||||
if (!marshalled) {
|
||||
try {
|
||||
@@ -344,16 +475,38 @@ 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<PycObject>(), &mod, 0, disasm_flags,
|
||||
*pyc_output);
|
||||
das_out_file);
|
||||
} catch (std::exception& ex) {
|
||||
das_out_file.flush();
|
||||
das_out_file.close();
|
||||
fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what());
|
||||
return 1;
|
||||
}
|
||||
|
||||
das_out_file.flush();
|
||||
das_out_file.close();
|
||||
|
||||
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) {
|
||||
dc_out_file.flush();
|
||||
dc_out_file.close();
|
||||
fprintf(stderr, "Error decompyling %s: %s\n", infile, ex.what());
|
||||
return 1;
|
||||
}
|
||||
|
||||
dc_out_file.flush();
|
||||
dc_out_file.close();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user