Merge pull request #564 from whoami730/exceptions

Parse and display exception table
This commit is contained in:
Michael Hansen
2025-08-30 10:02:14 -07:00
committed by GitHub
5 changed files with 77 additions and 5 deletions

View File

@@ -600,3 +600,18 @@ void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
pyc_output << "\n";
}
}
void bc_exceptiontable(std::ostream& pyc_output, PycRef<PycCode> code,
int indent)
{
for (const auto& entry : code->exceptionTableEntries()) {
for (int i=0; i<indent; i++)
pyc_output << " ";
pyc_output << entry.start_offset << " to " << entry.end_offset
<< " -> " << entry.target << " [" << entry.stack_depth
<< "] " << (entry.push_lasti ? "lasti": "")
<< "\n";
}
}

View File

@@ -32,3 +32,5 @@ void print_const(std::ostream& pyc_output, PycRef<PycObject> obj, PycModule* mod
void bc_next(PycBuffer& source, PycModule* mod, int& opcode, int& operand, int& pos);
void bc_disasm(std::ostream& pyc_output, PycRef<PycCode> code, PycModule* mod,
int indent, unsigned flags);
void bc_exceptiontable(std::ostream& pyc_output, PycRef<PycCode> code,
int indent);

View File

@@ -128,3 +128,44 @@ PycRef<PycString> PycCode::getCellVar(PycModule* mod, int idx) const
? m_freeVars->get(idx - m_cellVars->size()).cast<PycString>()
: m_cellVars->get(idx).cast<PycString>();
}
int _parse_varint(PycBuffer& data, int& pos) {
int b = data.getByte();
pos += 1;
int val = b & 0x3F;
while (b & 0x40) {
val <<= 6;
b = data.getByte();
pos += 1;
val |= (b & 0x3F);
}
return val;
}
std::vector<PycExceptionTableEntry> PycCode::exceptionTableEntries() const
{
PycBuffer data(m_exceptTable->value(), m_exceptTable->length());
std::vector<PycExceptionTableEntry> entries;
int pos = 0;
while (!data.atEof()) {
int start = _parse_varint(data, pos) * 2;
int length = _parse_varint(data, pos) * 2;
int end = start + length;
int target = _parse_varint(data, pos) * 2;
int dl = _parse_varint(data, pos);
int depth = dl >> 1;
bool lasti = bool(dl & 1);
entries.push_back(PycExceptionTableEntry(start, end, target, depth, lasti));
}
return entries;
}

View File

@@ -8,6 +8,18 @@
class PycData;
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 {
public:
typedef std::vector<PycRef<PycString>> globals_t;
@@ -87,6 +99,8 @@ public:
m_globalsUsed.emplace_back(std::move(varname));
}
std::vector<PycExceptionTableEntry> exceptionTableEntries() const;
private:
int m_argCount, m_posOnlyArgCount, m_kwOnlyArgCount, m_numLocals;
int m_stackSize, m_flags;

View File

@@ -154,16 +154,16 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
iputs(pyc_output, indent + 1, "[Disassembly]\n");
bc_disasm(pyc_output, codeObj, mod, indent + 2, flags);
if (mod->verCompare(3, 11) >= 0) {
iputs(pyc_output, indent + 1, "[Exception Table]\n");
bc_exceptiontable(pyc_output, codeObj, indent+2);
}
if (mod->verCompare(1, 5) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) {
iprintf(pyc_output, indent + 1, "First Line: %d\n", codeObj->firstLine());
iputs(pyc_output, indent + 1, "[Line Number Table]\n");
output_object(codeObj->lnTable().cast<PycObject>(), mod, indent + 2, flags, pyc_output);
}
if (mod->verCompare(3, 11) >= 0 && (flags & Pyc::DISASM_PYCODE_VERBOSE) != 0) {
iputs(pyc_output, indent + 1, "[Exception Table]\n");
output_object(codeObj->exceptTable().cast<PycObject>(), mod, indent + 2, flags, pyc_output);
}
}
break;
case PycObject::TYPE_STRING: