【问题标题】:How can I inspect WAM code in SICStus Prolog如何在 SICStus Prolog 中检查 WAM 代码
【发布时间】:2019-08-31 09:04:28
【问题描述】:

在对 进行黑客攻击的背景下,我想看看 SICStus Prolog 生成的 代码。 例如,让我们剖析以下谓词!

is_list([]).
is_list([_|Es]) :- is_list(Es).

这是我现在正在做的事情:

  1. is_list/1的2个子句拆分为2个独立的谓词,并在前面加上2个虚拟子句:

    is_list__clause1(dummy1). % 虚拟子句 is_list__clause1([])。 is_list__clause2(dummy2). % 虚拟子句 is_list__clause2([_|Es]) :- is_list(Es)。
  2. (Ab-)像这样使用 SICStus

    | ?- is_list__clause1(X). X = 虚拟 1 ? t … 0x7eff37281300:GET_NIL_X0 0x7eff37281304:继续 0x7eff37281308:END_OF_CLAUSEQ 用户:is_list__clause1/1 … | ?- is_list__clause2(X). X = 虚拟 2 ? t … 0x7eff37281150:GET_LIST_X0 0x7eff37281154: U2_VOID_XVAR 1,x(0) 0x7eff37281160:执行用户:is_list/1 0x7eff37281170:END_OF_CLAUSEQ 用户:is_list__clause2/1 …

这个输出——尽管有点神秘——让我对 WAM 级别的情况有所了解。我喜欢!

但是已经有一个更简单的方法......请帮忙!

【问题讨论】:

  • 你确定是 WAM 吗?见:SICStus Prolog—the first 25 years本来以为SWI-Prolog没有抽象机,后来发现是基于ZIPSWI-Prolog Implementation historySICStusWhat Is New In Release 4
  • 但是在 2019 年 4 月的 Sicstus 手册中,4.5.1 版本指出:The system consists of a WAM emulator written in C, a library and runtime system written in C and Prolog and an interpreter and a compiler written in Prolog. The Prolog engine is a Warren Abstract Machine (WAM) emulator [Warren 83].
  • 此版本早于第 4 版,并且由于版本似乎是完全重写的,因此很可能已将其忽略:The SICStus Emulator 由 Mats Carlsson 1991 年 9 月 -- 发现于:Prolog and Logic Programming Historical Sources Archive
  • @GuyCoder。我发现历史资料档案非常有趣。这对我来说是新的,所以你的 cmets 非常有帮助。不要让互联网拖累你。 ☮
  • 谢谢。我不会让互联网拖累我。我已经将我的重心从 StackOverflow 转移到了SWI-Prolog Discourse forum 上,通过 Prolog 在线帮助其他人。我把历史资料档案作为链接放在Useful Prolog references上。

标签: clpz sicstus-prolog warren-abstract-machine prolog-toplevel prolog sicstus-prolog warren-abstract-machine


【解决方案1】:

有一个更简单的方法:无证,不受支持,library(disassembler)

除了 WAM 指令之外,您还可以使用它以编程方式获取有关第一个参数索引的信息。有关详细信息,请参阅来源。

| ?- use_module(library(disassembler)).
% ...
yes
| ?- [user].
% compiling user...
| foo([],Ys,Ys). foo([X|Xs],Ys,[X|Zs]) :- foo(Xs,Ys,Zs). end_of_file.
% compiled user in module user, 89 msec 599696 bytes
yes
| ?- disassemble(foo/3).
% Predicate: user:foo/3 (user)
% Varcase: [4343940512-4343958960,4346212208-4343221120]
% Lstcase: [4346212212]
% Switch: [[]=4343940516], default: failcode
% clause indexed [var,number,atom,structure] (user)
%    4343940512: 'GET_NIL_X0'
%    4343940516: 'GET_X_VALUE_PROCEED'(x(1),x(2))
%    4343940528: 'END_OF_CLAUSEQ'(user:foo/3)
% clause indexed [var,list] (user)
%    4346212208: 'GET_LIST_X0'
%    4346212212: 'U2_XVAR_XVAR'(x(3,0),x(0,0))
%    4346212224: 'GET_LIST'(x(2))
%    4346212232: 'U2_XVAL_XVAR'(x(3),x(2,0))
%    4346212244: 'EXECUTE'(user:foo/3)
%    4346212256: 'END_OF_CLAUSEQ'(user:foo/3)
yes
| ?- 

【讨论】:

  • 是否也能看到 JIT 代码?
  • 没有很好的方法来查看发布版本中的 JIT 代码。在 Linux 上,您可以使用 sicstus -DSP_SPTI_PATH=perf 将配置文件信息转储到 /tmp 中的某个位置,包括目标代码(作为 ELF 二进制文件)。转储的信息包含一个 perf.map,它告诉哪个 elf 文件对应于哪个 Prolog 谓词,并且可以使用 objdump --disassemble-all 之类的东西来反汇编它。不幸的是,二进制文件包含数据和机器码的混合,因此反汇编程序很可能会混淆。
  • 如果您想查看您的 jit 代码在哪里花费时间,请使用 perf record sicstus -DSP_SPTI_PATH=perfperf annotate --objdump=sp_jit_objdump(或 perf top -objdump=sp_jit_objdump)。
  • 在其他平台上,例如macOS,你可以基于library/spti_verbose.* 构建一些东西。它目前只记录 jitted 过程,但它获得与 perf 支持相同的信息,因此您可以修改它以转储代码块并使用其他工具对其进行反汇编。要构建您自己的副本,请执行cp .../library/spti_verbose.{c,pl} . && splfr --no-hide-symbols spti_verbose.pl spti_verbose.c -o spti_verbose.dylib && sicstus -DSP_SPTI_PATH=./spti_verbose.dylib。这仍然存在数据混淆反汇编程序的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多