- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
阅读“每个程序员都应该知道的 97 件事”,我发现了一篇关于代码分析工具的有趣文章。
作者声称来自 Python 标准库的反汇编程序对于调试您的日常代码非常有用
这里是:“这个库(Python 标准库反汇编程序)可以反汇编的一件事是你的最后一个堆栈跟踪,给你关于哪个字节码指令抛出最后一个未捕获异常的准确反馈。”
但是书中并没有对此进行解释
那么有人知道上面的模块如何对调试有用吗?
最佳答案
虽然反汇编器可以作为一种工具来帮助您了解 Python 如何理解您编写的内容,但它并不是唯一的工具。还有其他工具也可以提供帮助。正如我们将看到的,其中一些可以协同工作。
所以这是一小段 Python:
def five():
return 5
print(five())
这里是使用我编写的跨平台反汇编器对其进行反汇编的一部分,它被称为 xdis :
# Python bytecode 3.4 (3310)
# Disassembled from Python 3.4.2 (default, May 17 2015, 22:17:04)
# [GCC 4.8.2]
# Timestamp in code: 1499405520 (2017-07-07 01:32:00)
# Source code size mod 2**32: 39 bytes
# Method Name: <module>
# Filename: five.py
# Argument count: 0
# Kw-only arguments: 0
# Number of locals: 0
# Stack size: 2
# Flags: 0x00000040 (NOFREE)
# First Line: 1
# Constants:
# 0: <code object five at 0x7f99dd4e88a0, file "five.py", line 1>
# 1: 'five'
# 2: None
# Names:
# 0: five
# 1: print
1:
LOAD_CONST 0 (<code object five at 0x7f99dd4e88a0, file "five.py", line 1>)
LOAD_CONST 1 ('five')
MAKE_FUNCTION 0 (0 positional, 0 name and default, 0 annotations)
STORE_NAME 0 (five)
3:
LOAD_NAME 1 (print)
LOAD_NAME 0 (five)
CALL_FUNCTION 0 (0 positional, 0 keyword pair)
CALL_FUNCTION 1 (1 positional, 0 keyword pair)
POP_TOP
LOAD_CONST 2 (None)
RETURN_VALUE
...
(这是 Python 3.4,其他版本的细节略有不同。)
首先要注意的是python认为这段代码来自一个路径名为five.py
的文件。如果您碰巧重命名了文件而不是 python 代码,这可能会使 Python 感到困惑。或者文件名可能是 tmp/five.py
而不是你应该寻找它。此外,在 Python 版本 3 和更高版本中,有文件的大小(模数 2**32)作为检查文件系统上的 five.py
是否是与 Python 在编译文件时看到的相同。
请注意代码的开头:我们正在加载一个常量对象,它恰好是一个函数的代码!然后是函数名称,最后调用 MAKE_FUNCTION
并将其存储在名为 five 的变量中。
如果您习惯了 C++、Go 或 Java 等不执行此操作的编译语言,那么有点不寻常的是,该函数是在您运行程序时当场创建的。如果我的程序之前有另一条指令,而是:
x = five() # five is hasn't been defined here!
def five(): ...
这会失败,因为 MAKE_FUNCTION 尚未运行,因此在开始时还没有定义五个。
现在我还建议您也可以使用调试器来学习它,我再次建议 trepan2 或 trepan3 内置反汇编命令它们,甚至是该程序集的解析器。
另一个可以解释反汇编的地方是在 Python 对代码进行优化的极少数情况下。
考虑这个 Python 源代码:
if 1:
y = 5
在这里,在大约 2.3 之后的 Python 版本中,只会注意到 if 1:
是多余的,并删除该代码。但如果你改为说:
x = 1
if x:
y = 5
这足以混淆 Python 以保留测试。反汇编是我认为您可以知道这一点的唯一方法。
最后一个方面是,当您在调试器中停止或遇到错误时,准确了解您所处的位置。您经常(但不总是)得到错误的那一行,但有时这可能会造成混淆。普通的Python 屏蔽了此处有用的信息,即指令偏移量,但我将向您展示如何获取这些信息以及出错的指令。
假设我的代码是:
prev = [100] + range(3)
x = prev[prev[prev[0]]]
如果我运行它,我将得到一个IndexError 异常。但它是哪个“prev”?
trepan2 (或 trepan3k )在此处公开指令指针。它还可以访问反汇编器和解析器。那么让我们看看如何在这里使用它:
trepan2 /tmp/boom.py
-> 2 prev = [100] + range(3)
(trepan2) next
(/tmp/boom.py:3 @19): <module>
-- 3 x = prev[prev[prev[0]]]
(trepan2) next
(/tmp/boom.py:3 @32): <module>
!! 3 x = prev[prev[prev[0]]]
R=> (<type 'exceptions.IndexError'>, 'list index out of range', <traceback object at
(trepan2) info pc
PC offset is 32.
2 0 LOAD_CONST 0 100
3 BUILD_LIST 1
6 LOAD_NAME 0 0
9 LOAD_CONST 1 3
12 CALL_FUNCTION 1 1 positional, 0 keyword pair
15 BINARY_ADD None
16 STORE_NAME 1 1
3 19 LOAD_NAME 1 1
22 LOAD_NAME 1 1
25 LOAD_NAME 1 1
28 LOAD_CONST 2 0
31 BINARY_SUBSCR None
--> 32 BINARY_SUBSCR None
33 BINARY_SUBSCR None
34 STORE_NAME 2 2
37 LOAD_CONST 3 None
40 RETURN_VALUE None
好的。所以我们看到我们到底在哪里,偏移量 32(之前在偏移量@19 处停止后的@32),但这意味着什么? trepan 调试器会将其转换回 Python,因此您不必自己执行此操作:
(trepan2) deparse -p
instruction: 32 BINARY_SUBSCR
x = prev[prev[prev[0]]]
-------------
Contained in...
Grammar Symbol: binary_subscr
x = prev[prev[prev[0]]]
-------------------
(trepan2) prev
[100, 0, 1, 2]
然后,上面显示您处于偏移量 32(不是 31 或 33)并且特定的 prev 访问不是第一个访问 prev[0]
但prev[prev[0]]
之后的一个。
虽然在调试器中同时具有反汇编器和解析器,但您不必太多了解正在发生的事情。但我认为了解指令的作用或指令顺序是什么并没有什么坏处。
关于python - 使用反汇编程序调试错误的Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28435882/
我目前正在对一个 mmorpg 的二进制网络协议(protocol)进行逆向工程。我正在用 java 实现该协议(protocol)。 对于每个数据包类型,我将创建一个表示二进制数据的类。 例如,聊天
我正在尝试围绕现有类编写半透明包装器,我希望它能够模仿其他类的序列化。 例如,给定以下类: class Foo { [JsonConverter(CustomConverter)] s
是否有使用 Jackson 序列化和反序列化枚举集的简单方法? private enum Type { YES, NO } @JacksonXmlProperty(localName = "t
我很想知道当我们反序列化一个对象时会发生什么。 例如,如果我的类对象由许多其他对象组成,对象创建过程如何在反序列化过程中发生 最佳答案 对象是用默认的初始化字段创建的,然后用从串行流中获取的属性值填充
我正在尝试序列化和反序列化(使用 QDataStream 但这与这里无关)一个 enum class变量: enum class Type : char { Trivial, Comp
我不确定这到底有什么问题...它不会为我编译,我将它从 c 翻译成 C++(或尝试)...是的,我是初学者。谢谢! #include #include using namespace std; i
我遇到的问题与此处描述的问题非常相似:Combining type and field serializers case class(id: Option[UUID], otherValue:Stri
我们知道base中的apply()可以对数组的边距应用一个函数,边距应该是行或列。我想将边距扩大到“对角线” 和“反对角线”。结构看起来像 diagApply <- function(x, FUN,
我找到了 JSON serialization and deserialization to objects in Flutter 的例子但是如何使用像这样的人员列表来做到这一点: [ {
我有一个相当大的terms聚合结果,这些结果被加载到下拉列表中以提供filter功能。 可以说,我的下拉列表中有4000多种动物。我的另一个下拉列表有4种动物颜色。 例, animal --> ["d
我需要将 C# (.NET Framework 4.5.2) 中的一个类与 XML 序列化(反序列化),该类具有 string 的字典属性。键和 string[]数组值。我正在使用 Serializa
[已解决]应用给定的解决方案,效果很好! 程序的目的:在用户打开和关闭程序时保存/重新加载以前的数据。 我曾经用一个对象(obj)成功(反)序列化,现在我有两个不同类的不同对象。 我试图通过查看其他帖
问题 假设我有一个代表某事或其他的枚举: public enum ResultState { Found, Deleted, NotFound } 在我的序列化 json 中,
是否有取消 JSON 字符串的功能?我猜它不会内置到 JQuery 中,但它可以通过编写一个操纵字符串的脚本来实现吗?我在下面遇到了这个问题。 我正在使用 NYTimes API,但它不支持 JSON
对于这个问题,假设当对象完全写入流并成功读出时,或者当对象部分写入流并且读回对象时发生异常时,序列化/反序列化是原子的。假设写操作可能无法成功完成,例如因为停电了。 在Serializable的描述中
有谁知道时序检查是否仍在检测虚拟环境?我尝试使用 rdtsc 指令来获取 cpu 周期并比较真实 linux 机器和在 virtualbox 上运行的 linux 之间的结果。但结果似乎不稳定。有时,
我正在对一个(外部给定的)XML 文件进行操作,该文件具有以下形式的元素 10 20 30 40 50 60 70 80 我知道如何将属性作为属性处理(通过使用 [XmlAttri
我有一个通用的序列化器和反序列化器,用于通过网络连接发送的消息: public static async Task SerializeObject(Object obj) {
我正在考虑将当前基于 WCF 的应用程序迁移到 protobuf-net.Grpc。这似乎是可行的,但是我无法在不包含所有具有 [ProtoInclude] 属性的派生类的情况下使(DTO 类)基类的
我正在尝试将一些数据保存到文件中,但文件保存到的目录不正确。 using (StreamWriter sw = new StreamWriter(dir + "\\temp" + x + ".txt"
我是一名优秀的程序员,十分优秀!