Compare commits
23 Commits
e8e10f1419
...
5e70e1e084
| Author | SHA1 | Date | |
|---|---|---|---|
|
5e70e1e084
|
|||
|
1c413c5124
|
|||
|
49557e7580
|
|||
|
6c6aa159df
|
|||
|
b5983f505f
|
|||
|
7a0044914c
|
|||
|
3359b0e1b2
|
|||
|
8b8fe3020a
|
|||
|
|
a05ddec0d8 | ||
|
|
d8c6fdf711 | ||
|
|
577720302e | ||
|
|
38799f5cfb | ||
|
|
0e7be40367 | ||
|
|
ff0c1450b4 | ||
|
|
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
|
|
||||||
272
ASTree.cpp
272
ASTree.cpp
@@ -1,6 +1,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <unordered_set>
|
||||||
#include "ASTree.h"
|
#include "ASTree.h"
|
||||||
#include "FastStack.h"
|
#include "FastStack.h"
|
||||||
#include "pyc_numeric.h"
|
#include "pyc_numeric.h"
|
||||||
@@ -423,6 +424,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Pyc::CALL_A:
|
case Pyc::CALL_A:
|
||||||
|
// BEGIN ONESHOT TEMPORARY PATCH
|
||||||
|
case Pyc::CALL_KW_A:
|
||||||
|
// END ONESHOT PATCH
|
||||||
case Pyc::CALL_FUNCTION_A:
|
case Pyc::CALL_FUNCTION_A:
|
||||||
case Pyc::INSTRUMENTED_CALL_A:
|
case Pyc::INSTRUMENTED_CALL_A:
|
||||||
{
|
{
|
||||||
@@ -454,6 +458,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack.pop();
|
stack.pop();
|
||||||
PycRef<ASTNode> loadbuild = stack.top();
|
PycRef<ASTNode> loadbuild = stack.top();
|
||||||
stack.pop();
|
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();
|
int loadbuild_type = loadbuild.type();
|
||||||
if (loadbuild_type == ASTNode::NODE_LOADBUILDCLASS) {
|
if (loadbuild_type == ASTNode::NODE_LOADBUILDCLASS) {
|
||||||
PycRef<ASTNode> call = new ASTCall(function, pparamList, kwparamList);
|
PycRef<ASTNode> call = new ASTCall(function, pparamList, kwparamList);
|
||||||
@@ -467,13 +482,19 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack_hist.pop();
|
stack_hist.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// BEGIN ONESHOT TEMPORARY PATCH
|
||||||
KW_NAMES(i)
|
if (mod->verCompare(3, 13) >= 0 && opcode == Pyc::CALL_KW_A) {
|
||||||
Stores a reference to co_consts[consti] into an internal variable for use by CALL.
|
PycRef<PycTuple> kw_names = stack.top().cast<ASTObject>()->object().cast<PycTuple>();
|
||||||
co_consts[consti] must be a tuple of strings.
|
stack.pop();
|
||||||
New in version 3.11.
|
kwparams = kw_names->values().size();
|
||||||
*/
|
pparams = operand - kwparams;
|
||||||
if (mod->verCompare(3, 11) >= 0) {
|
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();
|
PycRef<ASTNode> object_or_map = stack.top();
|
||||||
if (object_or_map.type() == ASTNode::NODE_KW_NAMES_MAP) {
|
if (object_or_map.type() == ASTNode::NODE_KW_NAMES_MAP) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -513,12 +534,22 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
pparamList.push_front(param);
|
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();
|
PycRef<ASTNode> func = stack.top();
|
||||||
stack.pop();
|
stack.pop();
|
||||||
if ((opcode == Pyc::CALL_A || opcode == Pyc::INSTRUMENTED_CALL_A) &&
|
if ((opcode == Pyc::CALL_A || opcode == Pyc::INSTRUMENTED_CALL_A) &&
|
||||||
stack.top() == nullptr) {
|
mod->verCompare(3, 13) < 0 && stack.top() == nullptr) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
}
|
}
|
||||||
|
// END ONESHOT PATCH
|
||||||
|
|
||||||
stack.push(new ASTCall(func, pparamList, kwparamList));
|
stack.push(new ASTCall(func, pparamList, kwparamList));
|
||||||
}
|
}
|
||||||
@@ -607,6 +638,41 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack.push(call);
|
stack.push(call);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case Pyc::CALL_METHOD_A:
|
||||||
{
|
{
|
||||||
ASTCall::pparam_t pparamList;
|
ASTCall::pparam_t pparamList;
|
||||||
@@ -1231,8 +1297,12 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack = stack_hist.top();
|
if (!stack_hist.empty()) {
|
||||||
stack_hist.pop();
|
stack = stack_hist.top();
|
||||||
|
stack_hist.pop();
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Warning: Stack history is empty, something wrong might have happened\n");
|
||||||
|
}
|
||||||
|
|
||||||
PycRef<ASTBlock> prev = curblock;
|
PycRef<ASTBlock> prev = curblock;
|
||||||
PycRef<ASTBlock> nil;
|
PycRef<ASTBlock> nil;
|
||||||
@@ -1313,6 +1383,19 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
bool push = true;
|
bool push = true;
|
||||||
|
|
||||||
do {
|
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();
|
blocks.pop();
|
||||||
|
|
||||||
if (!blocks.empty())
|
if (!blocks.empty())
|
||||||
@@ -1380,7 +1463,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
blocks.push(except);
|
blocks.push(except);
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
prev = nil;
|
||||||
} else {
|
} else {
|
||||||
@@ -1389,10 +1473,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
|
|
||||||
} while (prev != nil);
|
} while (prev != nil);
|
||||||
|
|
||||||
curblock = blocks.top();
|
if (!blocks.empty()) {
|
||||||
|
curblock = blocks.top();
|
||||||
if (curblock->blktype() == ASTBlock::BLK_EXCEPT) {
|
if (curblock->blktype() == ASTBlock::BLK_EXCEPT)
|
||||||
curblock->setEnd(pos+offs);
|
curblock->setEnd(pos+offs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1556,6 +1640,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
break;
|
break;
|
||||||
case Pyc::MAKE_CLOSURE_A:
|
case Pyc::MAKE_CLOSURE_A:
|
||||||
case Pyc::MAKE_FUNCTION_A:
|
case Pyc::MAKE_FUNCTION_A:
|
||||||
|
// BEGIN ONESHOT TEMPORARY PATCH
|
||||||
|
case Pyc::MAKE_FUNCTION:
|
||||||
|
// END ONESHOT PATCH
|
||||||
{
|
{
|
||||||
PycRef<ASTNode> fun_code = stack.top();
|
PycRef<ASTNode> fun_code = stack.top();
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -1569,19 +1656,49 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ASTFunction::defarg_t defArgs, kwDefArgs;
|
ASTFunction::defarg_t defArgs, kwDefArgs;
|
||||||
const int defCount = operand & 0xFF;
|
// BEGIN ONESHOT TEMPORARY PATCH
|
||||||
const int kwDefCount = (operand >> 8) & 0xFF;
|
if (mod->verCompare(3, 6) < 0)
|
||||||
for (int i = 0; i < defCount; ++i) {
|
{
|
||||||
defArgs.push_front(stack.top());
|
const int defCount = operand & 0xFF;
|
||||||
stack.pop();
|
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) {
|
else if (mod->verCompare(3, 13) < 0)
|
||||||
kwDefArgs.push_front(stack.top());
|
{
|
||||||
stack.pop();
|
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));
|
stack.push(new ASTFunction(fun_code, defArgs, kwDefArgs));
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case Pyc::NOP:
|
||||||
break;
|
break;
|
||||||
case Pyc::POP_BLOCK:
|
case Pyc::POP_BLOCK:
|
||||||
@@ -1612,9 +1729,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack = stack_hist.top();
|
stack = stack_hist.top();
|
||||||
stack_hist.pop();
|
stack_hist.pop();
|
||||||
} else {
|
} 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;
|
PycRef<ASTBlock> tmp = curblock;
|
||||||
blocks.pop();
|
blocks.pop();
|
||||||
|
|
||||||
@@ -1769,7 +1894,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
else
|
else
|
||||||
curblock->append(new ASTPrint(stack.top(), stream));
|
curblock->append(new ASTPrint(stack.top(), stream));
|
||||||
stack.pop();
|
stack.pop();
|
||||||
stream->setProcessed();
|
if (stream)
|
||||||
|
stream->setProcessed();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Pyc::PRINT_NEWLINE:
|
case Pyc::PRINT_NEWLINE:
|
||||||
@@ -1797,7 +1923,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
else
|
else
|
||||||
curblock->append(new ASTPrint(nullptr, stream));
|
curblock->append(new ASTPrint(nullptr, stream));
|
||||||
stack.pop();
|
stack.pop();
|
||||||
stream->setProcessed();
|
if (stream)
|
||||||
|
stream->setProcessed();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Pyc::RAISE_VARARGS_A:
|
case Pyc::RAISE_VARARGS_A:
|
||||||
@@ -1842,7 +1969,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
curblock = blocks.top();
|
curblock = blocks.top();
|
||||||
curblock->append(prev.cast<ASTNode>());
|
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;
|
break;
|
||||||
@@ -1921,7 +2050,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
||||||
if (none != NULL) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2029,7 +2159,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||||
tup.cast<ASTTuple>()->add(attr);
|
tup.cast<ASTTuple>()->add(attr);
|
||||||
else
|
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) {
|
if (--unpack <= 0) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -2064,7 +2195,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||||
tup.cast<ASTTuple>()->add(name);
|
tup.cast<ASTTuple>()->add(name);
|
||||||
else
|
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) {
|
if (--unpack <= 0) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -2104,7 +2236,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||||
tup.cast<ASTTuple>()->add(name);
|
tup.cast<ASTTuple>()->add(name);
|
||||||
else
|
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) {
|
if (--unpack <= 0) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -2163,7 +2296,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||||
tup.cast<ASTTuple>()->add(name);
|
tup.cast<ASTTuple>()->add(name);
|
||||||
else
|
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) {
|
if (--unpack <= 0) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -2205,7 +2339,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||||
tup.cast<ASTTuple>()->add(name);
|
tup.cast<ASTTuple>()->add(name);
|
||||||
else
|
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) {
|
if (--unpack <= 0) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -2326,7 +2461,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
if (tup.type() == ASTNode::NODE_TUPLE)
|
if (tup.type() == ASTNode::NODE_TUPLE)
|
||||||
tup.cast<ASTTuple>()->add(save);
|
tup.cast<ASTTuple>()->add(save);
|
||||||
else
|
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) {
|
if (--unpack <= 0) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
@@ -2481,6 +2617,9 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
as no-ops. */
|
as no-ops. */
|
||||||
break;
|
break;
|
||||||
case Pyc::PUSH_NULL:
|
case Pyc::PUSH_NULL:
|
||||||
|
// BEGIN ONESHOT TEMPORARY PATCH
|
||||||
|
case Pyc::BEGIN_FINALLY:
|
||||||
|
// END ONESHOT PATCH
|
||||||
stack.push(nullptr);
|
stack.push(nullptr);
|
||||||
break;
|
break;
|
||||||
case Pyc::GEN_START_A:
|
case Pyc::GEN_START_A:
|
||||||
@@ -2504,6 +2643,34 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack.push(next_tup);
|
stack.push(next_tup);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case Pyc::BINARY_SLICE:
|
||||||
{
|
{
|
||||||
PycRef<ASTNode> end = stack.top();
|
PycRef<ASTNode> end = stack.top();
|
||||||
@@ -2578,7 +2745,10 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
cleanBuild = false;
|
||||||
return new ASTNodeList(defblock->nodes());
|
return new ASTNodeList(defblock->nodes());
|
||||||
}
|
}
|
||||||
@@ -2590,7 +2760,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stack_hist.size()) {
|
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()) {
|
while (stack_hist.size()) {
|
||||||
stack_hist.pop();
|
stack_hist.pop();
|
||||||
@@ -2598,7 +2769,8 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (blocks.size() > 1) {
|
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) {
|
while (blocks.size() > 1) {
|
||||||
PycRef<ASTBlock> tmp = blocks.top();
|
PycRef<ASTBlock> tmp = blocks.top();
|
||||||
@@ -2773,6 +2945,8 @@ void print_formatted_value(PycRef<ASTFormattedValue> formatted_value, PycModule*
|
|||||||
pyc_output << "}";
|
pyc_output << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unordered_set<ASTNode *> node_seen;
|
||||||
|
|
||||||
void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output)
|
void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output)
|
||||||
{
|
{
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
@@ -2781,6 +2955,12 @@ void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node_seen.find((ASTNode *)node) != node_seen.end()) {
|
||||||
|
fputs("WARNING: Circular reference detected\n", stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node_seen.insert((ASTNode *)node);
|
||||||
|
|
||||||
switch (node->type()) {
|
switch (node->type()) {
|
||||||
case ASTNode::NODE_BINARY:
|
case ASTNode::NODE_BINARY:
|
||||||
case ASTNode::NODE_COMPARE:
|
case ASTNode::NODE_COMPARE:
|
||||||
@@ -3002,6 +3182,12 @@ void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output)
|
|||||||
case ASTNode::NODE_BLOCK:
|
case ASTNode::NODE_BLOCK:
|
||||||
{
|
{
|
||||||
PycRef<ASTBlock> blk = node.cast<ASTBlock>();
|
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)
|
if (blk->blktype() == ASTBlock::BLK_ELSE && blk->size() == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3436,10 +3622,12 @@ void print_src(PycRef<ASTNode> node, PycModule* mod, std::ostream& pyc_output)
|
|||||||
pyc_output << "<NODE:" << node->type() << ">";
|
pyc_output << "<NODE:" << node->type() << ">";
|
||||||
fprintf(stderr, "Unsupported Node type: %d\n", node->type());
|
fprintf(stderr, "Unsupported Node type: %d\n", node->type());
|
||||||
cleanBuild = false;
|
cleanBuild = false;
|
||||||
|
node_seen.erase((ASTNode *)node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanBuild = true;
|
cleanBuild = true;
|
||||||
|
node_seen.erase((ASTNode *)node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool print_docstring(PycRef<PycObject> obj, int indent, PycModule* mod,
|
bool print_docstring(PycRef<PycObject> obj, int indent, PycModule* mod,
|
||||||
@@ -3456,8 +3644,16 @@ bool print_docstring(PycRef<PycObject> obj, int indent, PycModule* mod,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unordered_set<PycCode *> code_seen;
|
||||||
|
|
||||||
void decompyle(PycRef<PycCode> code, PycModule* mod, std::ostream& pyc_output)
|
void decompyle(PycRef<PycCode> code, PycModule* mod, std::ostream& pyc_output)
|
||||||
{
|
{
|
||||||
|
if (code_seen.find((PycCode *)code) != code_seen.end()) {
|
||||||
|
fputs("WARNING: Circular reference detected\n", stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
code_seen.insert((PycCode *)code);
|
||||||
|
|
||||||
PycRef<ASTNode> source = BuildFromCode(code, mod);
|
PycRef<ASTNode> source = BuildFromCode(code, mod);
|
||||||
|
|
||||||
PycRef<ASTNodeList> clean = source.cast<ASTNodeList>();
|
PycRef<ASTNodeList> clean = source.cast<ASTNodeList>();
|
||||||
@@ -3551,4 +3747,6 @@ void decompyle(PycRef<PycCode> code, PycModule* mod, std::ostream& pyc_output)
|
|||||||
start_line(cur_indent, pyc_output);
|
start_line(cur_indent, pyc_output);
|
||||||
pyc_output << "# WARNING: Decompyle incomplete\n";
|
pyc_output << "# WARNING: Decompyle incomplete\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code_seen.erase((PycCode *)code);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ elseif(MSVC)
|
|||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
endif()
|
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})
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
add_library(pycxx STATIC
|
add_library(pycxx STATIC
|
||||||
@@ -62,15 +66,10 @@ add_library(pycxx STATIC
|
|||||||
bytes/python_3_11.cpp
|
bytes/python_3_11.cpp
|
||||||
bytes/python_3_12.cpp
|
bytes/python_3_12.cpp
|
||||||
bytes/python_3_13.cpp
|
bytes/python_3_13.cpp
|
||||||
|
bytes/python_3_14.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(pycdas pycdas.cpp)
|
add_executable(pycdc pycdas.cpp ASTree.cpp ASTNode.cpp)
|
||||||
target_link_libraries(pycdas pycxx)
|
|
||||||
|
|
||||||
install(TARGETS pycdas
|
|
||||||
RUNTIME DESTINATION bin)
|
|
||||||
|
|
||||||
add_executable(pycdc pycdc.cpp ASTree.cpp ASTNode.cpp)
|
|
||||||
target_link_libraries(pycdc pycxx)
|
target_link_libraries(pycdc pycxx)
|
||||||
|
|
||||||
install(TARGETS pycdc
|
install(TARGETS pycdc
|
||||||
|
|||||||
14
bytecode.cpp
14
bytecode.cpp
@@ -39,6 +39,7 @@ DECLARE_PYTHON(3, 10)
|
|||||||
DECLARE_PYTHON(3, 11)
|
DECLARE_PYTHON(3, 11)
|
||||||
DECLARE_PYTHON(3, 12)
|
DECLARE_PYTHON(3, 12)
|
||||||
DECLARE_PYTHON(3, 13)
|
DECLARE_PYTHON(3, 13)
|
||||||
|
DECLARE_PYTHON(3, 14)
|
||||||
|
|
||||||
const char* Pyc::OpcodeName(int opcode)
|
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 11: return python_3_11_map(opcode);
|
||||||
case 12: return python_3_12_map(opcode);
|
case 12: return python_3_12_map(opcode);
|
||||||
case 13: return python_3_13_map(opcode);
|
case 13: return python_3_13_map(opcode);
|
||||||
|
case 14: return python_3_14_map(opcode);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -604,14 +606,14 @@ void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
|
|||||||
void bc_exceptiontable(std::ostream& pyc_output, PycRef<PycCode> code,
|
void bc_exceptiontable(std::ostream& pyc_output, PycRef<PycCode> code,
|
||||||
int indent)
|
int indent)
|
||||||
{
|
{
|
||||||
for (auto tuple: code->exceptTableEntries()) {
|
for (const auto& entry : code->exceptionTableEntries()) {
|
||||||
|
|
||||||
for (int i=0; i<indent; i++)
|
for (int i=0; i<indent; i++)
|
||||||
pyc_output << " ";
|
pyc_output << " ";
|
||||||
|
|
||||||
pyc_output << std::get<0>(tuple) << " to " << std::get<1>(tuple);
|
pyc_output << entry.start_offset << " to " << entry.end_offset
|
||||||
pyc_output << " -> " << std::get<2>(tuple) << " ";
|
<< " -> " << entry.target << " [" << entry.stack_depth
|
||||||
pyc_output << "[" << std::get<3>(tuple) << "] " << (std::get<4>(tuple) ? "lasti": "");
|
<< "] " << (entry.push_lasti ? "lasti": "")
|
||||||
pyc_output << "\n";
|
<< "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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(MAKE_FUNCTION) // Python 3.13 ->
|
||||||
OPCODE(TO_BOOL) // 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 */
|
/* Has parameter word */
|
||||||
OPCODE_A_FIRST(STORE_NAME) // Python 1.0 -> names[A]
|
OPCODE_A_FIRST(STORE_NAME) // Python 1.0 -> names[A]
|
||||||
OPCODE_A(DELETE_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(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_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(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 */
|
/* Instrumented opcodes */
|
||||||
OPCODE_A(INSTRUMENTED_LOAD_SUPER_ATTR) // Python 3.12 -> (see LOAD_SUPER_ATTR)
|
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_INSTRUCTION) // Python 3.12 -> A=(unused)
|
||||||
OPCODE_A(INSTRUMENTED_LINE) // Python 3.12 -> ???
|
OPCODE_A(INSTRUMENTED_LINE) // Python 3.12 -> ???
|
||||||
OPCODE_A(INSTRUMENTED_CALL_KW) // Python 3.13 -> (see CALL_KW)
|
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()
|
||||||
28
data.cpp
28
data.cpp
@@ -53,35 +53,43 @@ bool PycFile::atEof() const
|
|||||||
int PycFile::getByte()
|
int PycFile::getByte()
|
||||||
{
|
{
|
||||||
int ch = fgetc(m_stream);
|
int ch = fgetc(m_stream);
|
||||||
if (ch == EOF)
|
if (ch == EOF) {
|
||||||
ungetc(ch, m_stream);
|
fputs("PycFile::getByte(): Unexpected end of stream\n", stderr);
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PycFile::getBuffer(int bytes, void* buffer)
|
void PycFile::getBuffer(int bytes, void* buffer)
|
||||||
{
|
{
|
||||||
return (int)fread(buffer, 1, bytes, m_stream);
|
if (fread(buffer, 1, bytes, m_stream) != (size_t)bytes) {
|
||||||
|
fputs("PycFile::getBuffer(): Unexpected end of stream\n", stderr);
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* PycBuffer */
|
/* PycBuffer */
|
||||||
int PycBuffer::getByte()
|
int PycBuffer::getByte()
|
||||||
{
|
{
|
||||||
if (atEof())
|
if (atEof()) {
|
||||||
return EOF;
|
fputs("PycBuffer::getByte(): Unexpected end of stream\n", stderr);
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
int ch = (int)(*(m_buffer + m_pos));
|
int ch = (int)(*(m_buffer + m_pos));
|
||||||
++m_pos;
|
++m_pos;
|
||||||
return ch & 0xFF; // Make sure it's just a byte!
|
return ch & 0xFF; // Make sure it's just a byte!
|
||||||
}
|
}
|
||||||
|
|
||||||
int PycBuffer::getBuffer(int bytes, void* buffer)
|
void PycBuffer::getBuffer(int bytes, void* buffer)
|
||||||
{
|
{
|
||||||
if (m_pos + bytes > m_size)
|
if (m_pos + bytes > m_size) {
|
||||||
bytes = m_size - m_pos;
|
fputs("PycBuffer::getBuffer(): Unexpected end of stream\n", stderr);
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
if (bytes != 0)
|
if (bytes != 0)
|
||||||
memcpy(buffer, (m_buffer + m_pos), bytes);
|
memcpy(buffer, (m_buffer + m_pos), bytes);
|
||||||
m_pos += bytes;
|
m_pos += bytes;
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int formatted_print(std::ostream& stream, const char* format, ...)
|
int formatted_print(std::ostream& stream, const char* format, ...)
|
||||||
|
|||||||
6
data.h
6
data.h
@@ -19,7 +19,7 @@ public:
|
|||||||
virtual bool atEof() const = 0;
|
virtual bool atEof() const = 0;
|
||||||
|
|
||||||
virtual int getByte() = 0;
|
virtual int getByte() = 0;
|
||||||
virtual int getBuffer(int bytes, void* buffer) = 0;
|
virtual void getBuffer(int bytes, void* buffer) = 0;
|
||||||
int get16();
|
int get16();
|
||||||
int get32();
|
int get32();
|
||||||
Pyc_INT64 get64();
|
Pyc_INT64 get64();
|
||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
bool atEof() const override;
|
bool atEof() const override;
|
||||||
|
|
||||||
int getByte() override;
|
int getByte() override;
|
||||||
int getBuffer(int bytes, void* buffer) override;
|
void getBuffer(int bytes, void* buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FILE* m_stream;
|
FILE* m_stream;
|
||||||
@@ -50,7 +50,7 @@ public:
|
|||||||
bool atEof() const override { return (m_pos == m_size); }
|
bool atEof() const override { return (m_pos == m_size); }
|
||||||
|
|
||||||
int getByte() override;
|
int getByte() override;
|
||||||
int getBuffer(int bytes, void* buffer) override;
|
void getBuffer(int bytes, void* buffer) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const unsigned char* m_buffer;
|
const unsigned char* m_buffer;
|
||||||
|
|||||||
18
pyc_code.cpp
18
pyc_code.cpp
@@ -67,8 +67,8 @@ void PycCode::load(PycData* stream, PycModule* mod)
|
|||||||
if (mod->verCompare(3, 8) < 0) {
|
if (mod->verCompare(3, 8) < 0) {
|
||||||
// Remap flags to new values introduced in 3.8
|
// Remap flags to new values introduced in 3.8
|
||||||
if (m_flags & 0xF0000000)
|
if (m_flags & 0xF0000000)
|
||||||
throw std::runtime_error("Cannot remap unexpected flags");
|
fprintf(stderr, "Remapping flags (%08X) may not be correct\n", m_flags);
|
||||||
m_flags = (m_flags & 0xFFFF) | ((m_flags & 0xFFF0000) << 4);
|
m_flags = (m_flags & 0x1FFF) | ((m_flags & 0xFFFE000) << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_code = LoadObject(stream, mod).cast<PycString>();
|
m_code = LoadObject(stream, mod).cast<PycString>();
|
||||||
@@ -133,23 +133,23 @@ int _parse_varint(PycBuffer& data, int& pos) {
|
|||||||
int b = data.getByte();
|
int b = data.getByte();
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|
||||||
int val = b & 63;
|
int val = b & 0x3F;
|
||||||
while (b & 64) {
|
while (b & 0x40) {
|
||||||
val <<= 6;
|
val <<= 6;
|
||||||
|
|
||||||
b = data.getByte();
|
b = data.getByte();
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|
||||||
val |= (b & 63);
|
val |= (b & 0x3F);
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<PycCode::exception_table_entry_t> PycCode::exceptTableEntries() const
|
std::vector<PycExceptionTableEntry> PycCode::exceptionTableEntries() const
|
||||||
{
|
{
|
||||||
PycBuffer data(m_exceptTable->value(), m_exceptTable->length());
|
PycBuffer data(m_exceptTable->value(), m_exceptTable->length());
|
||||||
|
|
||||||
std::vector<exception_table_entry_t> entries;
|
std::vector<PycExceptionTableEntry> entries;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (!data.atEof()) {
|
while (!data.atEof()) {
|
||||||
@@ -164,8 +164,8 @@ std::vector<PycCode::exception_table_entry_t> PycCode::exceptTableEntries() cons
|
|||||||
int depth = dl >> 1;
|
int depth = dl >> 1;
|
||||||
bool lasti = bool(dl & 1);
|
bool lasti = bool(dl & 1);
|
||||||
|
|
||||||
entries.emplace_back(start, end, target, depth, lasti);
|
entries.push_back(PycExceptionTableEntry(start, end, target, depth, lasti));
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|||||||
16
pyc_code.h
16
pyc_code.h
@@ -8,6 +8,18 @@
|
|||||||
class PycData;
|
class PycData;
|
||||||
class PycModule;
|
class PycModule;
|
||||||
|
|
||||||
|
class PycExceptionTableEntry {
|
||||||
|
public:
|
||||||
|
int start_offset; // inclusive
|
||||||
|
int end_offset; // exclusive
|
||||||
|
int target;
|
||||||
|
int stack_depth;
|
||||||
|
bool push_lasti;
|
||||||
|
|
||||||
|
PycExceptionTableEntry(int m_start_offset, int m_end_offset, int m_target, int m_stack_depth, bool m_push_lasti) :
|
||||||
|
start_offset(m_start_offset), end_offset(m_end_offset), target(m_target), stack_depth(m_stack_depth), push_lasti(m_push_lasti) {};
|
||||||
|
};
|
||||||
|
|
||||||
class PycCode : public PycObject {
|
class PycCode : public PycObject {
|
||||||
public:
|
public:
|
||||||
typedef std::vector<PycRef<PycString>> globals_t;
|
typedef std::vector<PycRef<PycString>> globals_t;
|
||||||
@@ -87,9 +99,7 @@ public:
|
|||||||
m_globalsUsed.emplace_back(std::move(varname));
|
m_globalsUsed.emplace_back(std::move(varname));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::tuple<int, int, int, int, bool> exception_table_entry_t;
|
std::vector<PycExceptionTableEntry> exceptionTableEntries() const;
|
||||||
|
|
||||||
std::vector<exception_table_entry_t> exceptTableEntries() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_argCount, m_posOnlyArgCount, m_kwOnlyArgCount, m_numLocals;
|
int m_argCount, m_posOnlyArgCount, m_kwOnlyArgCount, m_numLocals;
|
||||||
|
|||||||
@@ -182,6 +182,12 @@ void PycModule::setVersion(unsigned int magic)
|
|||||||
m_unicode = true;
|
m_unicode = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MAGIC_3_14:
|
||||||
|
m_maj = 3;
|
||||||
|
m_min = 14;
|
||||||
|
m_unicode = true;
|
||||||
|
break;
|
||||||
|
|
||||||
/* Bad Magic detected */
|
/* Bad Magic detected */
|
||||||
default:
|
default:
|
||||||
m_maj = -1;
|
m_maj = -1;
|
||||||
@@ -197,7 +203,7 @@ bool PycModule::isSupportedVersion(int major, int minor)
|
|||||||
case 2:
|
case 2:
|
||||||
return (minor >= 0 && minor <= 7);
|
return (minor >= 0 && minor <= 7);
|
||||||
case 3:
|
case 3:
|
||||||
return (minor >= 0 && minor <= 12);
|
return (minor >= 0 && minor <= 14);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ enum PycMagic {
|
|||||||
MAGIC_3_11 = 0x0A0D0DA7,
|
MAGIC_3_11 = 0x0A0D0DA7,
|
||||||
MAGIC_3_12 = 0x0A0D0DCB,
|
MAGIC_3_12 = 0x0A0D0DCB,
|
||||||
MAGIC_3_13 = 0x0A0D0DF3,
|
MAGIC_3_13 = 0x0A0D0DF3,
|
||||||
|
MAGIC_3_14 = 0x0A0D0E2B,
|
||||||
|
|
||||||
INVALID = 0,
|
INVALID = 0,
|
||||||
};
|
};
|
||||||
|
|||||||
194
pycdas.cpp
194
pycdas.cpp
@@ -1,12 +1,30 @@
|
|||||||
|
#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 <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <unordered_set>
|
||||||
#include "pyc_module.h"
|
#include "pyc_module.h"
|
||||||
#include "pyc_numeric.h"
|
#include "pyc_numeric.h"
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
|
#include "ASTree.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
# define PATHSEP '\\'
|
# define PATHSEP '\\'
|
||||||
@@ -14,6 +32,68 @@
|
|||||||
# define PATHSEP '/'
|
# define PATHSEP '/'
|
||||||
#endif
|
#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[] = {
|
static const char* flag_names[] = {
|
||||||
"CO_OPTIMIZED", "CO_NEWLOCALS", "CO_VARARGS", "CO_VARKEYWORDS",
|
"CO_OPTIMIZED", "CO_NEWLOCALS", "CO_VARARGS", "CO_VARKEYWORDS",
|
||||||
"CO_NESTED", "CO_GENERATOR", "CO_NOFREE", "CO_COROUTINE",
|
"CO_NESTED", "CO_GENERATOR", "CO_NOFREE", "CO_COROUTINE",
|
||||||
@@ -73,6 +153,8 @@ static void iprintf(std::ostream& pyc_output, int indent, const char* fmt, ...)
|
|||||||
va_end(varargs);
|
va_end(varargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unordered_set<PycObject *> out_seen;
|
||||||
|
|
||||||
void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
||||||
unsigned flags, std::ostream& pyc_output)
|
unsigned flags, std::ostream& pyc_output)
|
||||||
{
|
{
|
||||||
@@ -81,6 +163,12 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (out_seen.find((PycObject *)obj) != out_seen.end()) {
|
||||||
|
fputs("WARNING: Circular reference detected\n", stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out_seen.insert((PycObject *)obj);
|
||||||
|
|
||||||
switch (obj->type()) {
|
switch (obj->type()) {
|
||||||
case PycObject::TYPE_CODE:
|
case PycObject::TYPE_CODE:
|
||||||
case PycObject::TYPE_CODE2:
|
case PycObject::TYPE_CODE2:
|
||||||
@@ -104,7 +192,7 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
|||||||
unsigned int orig_flags = codeObj->flags();
|
unsigned int orig_flags = codeObj->flags();
|
||||||
if (mod->verCompare(3, 8) < 0) {
|
if (mod->verCompare(3, 8) < 0) {
|
||||||
// Remap flags back to the value stored in the PyCode object
|
// 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);
|
iprintf(pyc_output, indent + 1, "Flags: 0x%08X", orig_flags);
|
||||||
print_coflags(codeObj->flags(), pyc_output);
|
print_coflags(codeObj->flags(), pyc_output);
|
||||||
@@ -246,28 +334,27 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
|||||||
default:
|
default:
|
||||||
iprintf(pyc_output, indent, "<TYPE: %d>\n", obj->type());
|
iprintf(pyc_output, indent, "<TYPE: %d>\n", obj->type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_seen.erase((PycObject *)obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
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* infile = nullptr;
|
||||||
|
const char* outfile = nullptr;
|
||||||
bool marshalled = false;
|
bool marshalled = false;
|
||||||
const char* version = nullptr;
|
const char* version = nullptr;
|
||||||
unsigned disasm_flags = 0;
|
unsigned disasm_flags = 0;
|
||||||
std::ostream* pyc_output = &std::cout;
|
bool unitbuf = false;
|
||||||
std::ofstream out_file;
|
std::ofstream dc_out_file;
|
||||||
|
std::ofstream das_out_file;
|
||||||
|
|
||||||
for (int arg = 1; arg < argc; ++arg) {
|
for (int arg = 1; arg < argc; ++arg) {
|
||||||
if (strcmp(argv[arg], "-o") == 0) {
|
if (strcmp(argv[arg], "-o") == 0) {
|
||||||
if (arg + 1 < argc) {
|
if (arg + 1 < argc) {
|
||||||
const char* filename = argv[++arg];
|
outfile = 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;
|
|
||||||
} else {
|
} else {
|
||||||
fputs("Option '-o' requires a filename\n", stderr);
|
fputs("Option '-o' requires a filename\n", stderr);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -288,18 +375,25 @@ int main(int argc, char* argv[])
|
|||||||
} else if (strcmp(argv[arg], "--help") == 0 || strcmp(argv[arg], "-h") == 0) {
|
} else if (strcmp(argv[arg], "--help") == 0 || strcmp(argv[arg], "-h") == 0) {
|
||||||
fprintf(stderr, "Usage: %s [options] input.pyc\n\n", argv[0]);
|
fprintf(stderr, "Usage: %s [options] input.pyc\n\n", argv[0]);
|
||||||
fputs("Options:\n", stderr);
|
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(" -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(" -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(" --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(" --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);
|
fputs(" --help Show this help text and then exit\n", stderr);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (strcmp(argv[arg], "--unitbuf") == 0) {
|
||||||
|
unitbuf = true;
|
||||||
} else if (argv[arg][0] == '-') {
|
} else if (argv[arg][0] == '-') {
|
||||||
fprintf(stderr, "Error: Unrecognized argument %s\n", argv[arg]);
|
fprintf(stderr, "Error: Unrecognized argument %s\n", argv[arg]);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else if (!infile) {
|
||||||
infile = argv[arg];
|
infile = argv[arg];
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: Only one input file allowed, got %s and %s\n",
|
||||||
|
infile, argv[arg]);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,6 +402,54 @@ int main(int argc, char* argv[])
|
|||||||
return 1;
|
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;
|
PycModule mod;
|
||||||
if (!marshalled) {
|
if (!marshalled) {
|
||||||
try {
|
try {
|
||||||
@@ -333,16 +475,38 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
const char* dispname = strrchr(infile, PATHSEP);
|
const char* dispname = strrchr(infile, PATHSEP);
|
||||||
dispname = (dispname == NULL) ? infile : dispname + 1;
|
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(), mod.minorVer(),
|
||||||
(mod.majorVer() < 3 && mod.isUnicode()) ? " -U" : "");
|
(mod.majorVer() < 3 && mod.isUnicode()) ? " -U" : "");
|
||||||
try {
|
try {
|
||||||
output_object(mod.code().try_cast<PycObject>(), &mod, 0, disasm_flags,
|
output_object(mod.code().try_cast<PycObject>(), &mod, 0, disasm_flags,
|
||||||
*pyc_output);
|
das_out_file);
|
||||||
} catch (std::exception& ex) {
|
} catch (std::exception& ex) {
|
||||||
|
das_out_file.flush();
|
||||||
|
das_out_file.close();
|
||||||
fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what());
|
fprintf(stderr, "Error disassembling %s: %s\n", infile, ex.what());
|
||||||
return 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user