PostScript でデバッグするにはどうすればよいですか? Linux で GhostView/GhostScript を使用できますが、スタックや辞書などを表示できません。
3 に答える
最小限のデバッガー
本当に便利なハックを発見しました。
<<
/break{ /hook /pause load store }
/cont{ /hook {} store }
/doprompt{
(\nbreak>)print
flush(%lineedit)(r)file
cvx {exec}stopped pop }
/pause{ doprompt }
/hook{}
>> begin
これは8行のEMBEDDABLEデバッガーです。私はこれを8086エミュレーター用に作成しました。hook
メインループに入れ、次のフックで一時停止をトリガーするプロシージャを入れます(疑わしいOPCODEbreak
プロシージャに入れます。フックは、ブレークが最初の効果を発揮する場所です)。フックコールは一時停止し、コールを一時停止しますdoprompt
。これにより、1行の「break>」プロンプトが表示されます。ここに入力すると、フックがクリアされて回転し続け、別のフックに遭遇cont
するまで一時停止を実行しません。break
プロンプトで値を調べてコードを実行することもできますが、 Enterキーを押すとnbの実行が再開されるため、追加の行が必要な場合は、doprompt
またはpause
行の終わりに。コマンドの実行中はエラーは無視されます(デバッガーがプログラムをクラッシュさせたくない場合は、ばかげています!)。一時停止とプロンプトを組み合わせて名前を削除できると思います。ただし、ここでの目標は、マシンの効率ではなく、概念の明確なコレクションです。このコードは、他のコードのデバッグにまったく役立つため、スキャンと検証が簡単である必要があります。
これはどのようにデバッガーであり、行を読み取るだけですか?!
=
値を==
調査する必要があることを忘れないでください。forall
アレイなどget
を破壊します。あなたがどこにいるのかを本当に知るためにcountexecstack array execstack ==
、caboodle全体の読みやすいダンプを作成してください。つまり、実行スタック内の現在の位置のバックトレースであり、現在のフレームが戻ったときに再開されるのを待っている、部分的に実行されたすべてのプロシージャとファイルのテールが含まれます。
「printf」
printf
プログラムをインストルメント化する(いわばsを追加する)だけで、デバッガー自体がなくても実行できるデバッグは非常にたくさんあります。
ちょうど今、デバッガー自体が次のような非常に巧妙なものでクラッシュしていたため、デバッガーが私を助けることができないというエラーに遭遇しました
/E [ 0 0 10 ] def %eye point
/crackE { % set pointers into E
/ex E 0 1 getinterval cvx def
/ey E 1 1 getinterval cvx def
/ez E 2 1 getinterval cvx def
} def crackE
だから私が調査していた実際のエラーは
GPL Ghostscript 8.62 (2008-02-29)
Copyright (C) 2008 Artifex Software, Inc. All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Error: /stackunderflow in --forall--
Operand stack:
--nostringval--
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push 1905 1 3 %oparray_pop 1904 1 3 %oparray_pop 1888 1 3 %oparray_pop 1771 1 3 %oparray_pop --nostringval-- %errorexec_pop .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- 0.238095 0.047619 0.952381 --nostringval-- %for_real_continue 68.5714 17.1429 360.048 --nostringval-- %for_real_continue --nostringval--
Dictionary stack:
--dict:1151/1684(ro)(G)-- --dict:0/20(G)-- --dict:121/200(L)-- --dict:13/20(L)-- --dict:1/2(L)--
Current allocation mode is local
Last OS error: 2
Current file position is 3241
GPL Ghostscript 8.62: Unrecoverable error, exit code 1
そして、私が本当に知る必要がある--nostringval--
のは、オペランドスタック上のそのことは実際には何であるかということだけです。
だから私はこれをプログラムの始めに置きました
/forall { pstack()= forall } bind def
何度も実行します
{MO matmul 0 --get-- --aload-- --pop-- proj action} エラー:-forall--の/ stackunderflow オペランドスタック: --nostringval-- ..。
エラーの直前は、==
データセットが欠落しているプロシージャ本体があることを通知する最後のスタックダンプ(を使用)です。
pstack
このようなものと比較して少し鈍いです
/args { dup 1 add copy -1 1 { -1 roll ==only ( ) print } for } def
/forall { 2 args (forall)= forall } bind def
これは、明らかに機能しているコード内の誤ったデータを追跡するのに役立ちます。これは、Distillerの非常に初期のバージョンが、自分自身をダンプする描画操作のみを定義することによって最適化された.psファイルを生成する方法でもあり、残りの計算は「抽出」されます。
いくつかのトリック
()= %print a newline
=string %built-in 128-byte buffer used by = and ==
/object =string cvs print %convert object to string and print without newline
/stack { count dup 1 add copy { = } repeat pop } def % this is the code for the stack operator
66 (#) dup 0 3 index put print %m non-destructively print a "char"
[以前、ここで「スタック」の代わりに「=」を記述しました。悪い失敗。編集:不足pop
しているものをに追加しました/stack
。]
errordictハッキング
エラーを調査する別の方法は、エラーハンドラーを変更することです。/stackunderflow
上記のエラーを調査するために、私は使用できたはずです
errordict/stackunderflow{dup == /stackunderflow signalerror}put
専門化する代わりにforall
。追記のこのかなり難解な側面について学ぶために、とを読んでerrordict
stop
くださいstopped
。そしてインタラクティブに、を覗いてみてerrordict{exch =only ==}forall
ください。signalerror
ghostscript.error
ではAdobeインタプリタで呼び出されます。その仕事は、スタックのスナップショットを取り、次にstop
execスタックをポップするために呼び出すことです。したがって、dup ==
こことpstack
上記は、の前のエラーの本質的に同じ「瞬間」ですstop
。対話型セッション(およびgsの通常モードの前のプログラム)は、execスタックのより深いところに.と同等の括弧で囲まれています//your-program stopped { handleerror } if
。これはhandleerror
、スナップショットを使用して(プログラムがパージされた後)、情報のないスタックの印刷出力とともにエラーレポートを印刷します。
誤ったプログラムの開始時に、さまざまなスタイルのエラーレポートを生成するためhandleerror
に見つけることができる代替品があります。(ehandle.ps)run
$errorを検査します
ここで私の例を読み直しているときに、これを発見しました。インタプリタがまだプロンプトを表示している場合は、エラー後にスタックを調査することもできます。$error
スタックのスナップショットなど、エラー情報が辞書に保存されます。
GS>[ 1 2 3 ] [4 5 6] bogus
Error: /undefined in bogus
Operand stack:
--nostringval-- --nostringval--
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- %loop_continue --nostringval-- --nostringval-- false 1 %stopped_push .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval--
Dictionary stack:
--dict:1168/1684(ro)(G)-- --dict:0/20(G)-- --dict:77/200(L)--
Current allocation mode is local
Current file position is 24
GS<2>
GS<2>$error{pop ==}forall
/dstack
/recordstacks
/globalmode
/newerror
/.nosetlocal
/estack
/errorinfo
/.inerror
/SubstituteFont
/position
/binary
/ostack
/command
/errorname
GS<2>$error/ostack get ==
[[1 2 3] [4 5 6]]
GS<2>
もちろん、ここではオブジェクトはまだスタック上にありました。しかし$error
、覗くことがあります。これを試さないでください:$error ===
。TMI。
取得できる非常に便利な情報の1つは、エラーが発生した時点での実行スタックのコピーである、の$error
きれいな印刷です。/estack
PS<3>$error /estack get ==
[ --quit--{ pop --quit--} false { quitflag false --def---dict- /
execdepth 2 --copy----get--1 --sub----put----end---dict- /doclose false
--put--interrupt } --loop----cvx--[ /quitflag false --def---dict- /
newerror false --put--/prompt --load----stopped--{ (
Error during prompt execution
)--print--handleerror --exit--} --if--{
mark /stmtfile (%statementedit)(r)--file----def--} --stopped--{ --
cleartomark---dict- /newerror --get--{ -dict- /errorname --get--/
undefinedfilename --ne--{ handleerror } --if---dict- /newerror false --
put----exit--} --if--} { --pop--stmtfile --end--{ --cvx----exec--} --
stopped---dict- --begin--{ handleerror stmtfile --closefile--} --if--}
--ifelse--checkquit ] { checkquit } { -dict- --begin--{ handleerror
stmtfile --closefile--} --if--} false -file- -file- -file- --repeat----
cvx--[ randcurve randwidth randcolor stroke ] 1 { flushpage newpath } {
newpath } --forall----cvx--[ dup length 2 gt { [ currentcolordict DEVICE
/nativecolorspace get get exec counttomark 2 add -1 roll DEVICE dup /
FillPoly get exec pop pstack ()= flushpage } { pop } ifelse ] [ ] { pop
pstack ()= flushpage } { x_max width 0.50 add def (
intersect polygon edges with scanlines)= /P poly poly length 1 sub get
def [ poly { Q exch def x_max miny floor cvi 0.50 add 1 maxy ceiling cvi
0.50 sub { 1 index exch -0.50 1 index 4 2 roll P aload pop Q aload pop
.intersect { 2 array astore exch } if } for pop /P Q def } forall ] (
sort scanline intersection list)= dup { 1 index 1 get 1 index 1 get eq
{ exch 0 get exch 0 get lt } { exch 1 get exch 1 get lt } ifelse } qsort
(set pixels on each scanline)= aload length 2 idiv { exch aload pop 3 2
roll aload pop /USEDRAWLINE where { pop r g b 7 3 roll currentdict
DrawLine } { pop 3 2 roll exch 1 exch dup width ge { pop width 1 sub }
if { r g b 4 3 roll 2 index currentdict PutPix } for pop } ifelse }
repeat end } --forall----cvx--[ aload pop .maxmin ] [ [ 16 154 ] [ 16
154 ] ] { pop .maxmin } ]
PS<3>
今ではそのほとんどがおそらくぎこちないものになり、上位のいくつかの部分は読めないかもしれません。この出力は、作成中の私自身のポストスクリプトインタープリターからのものであり、すべてのオブジェクトが完全にアクセスできます。しかし、上部を見ないでください。下部を見てください。配列の最後の要素は、スタックの最上位の要素です。/command
これは、次に実行されなかったはずのコードです/errorname
。その小さな追記の断片は、問題がソースのどこにあるかを見つけるのに役立ちます。上記の私の場合、エラーが何であれ、前に..が.maxmin
前にある呼び出しをソースで検索する必要があります。pop
executive
プロンプトを取得するために呼び出す
プリンタのインタプリタとのシリアルセッションまたはTelnetセッションがある場合は、 Enterキーをexecutive
数回入力して押すことができます。入力時にの文字がエコーされない場合がありexecutive
ます。恐れることはありませんが、正しくつづります。それはあなたに挨拶とプロンプトを与えるはずです。
ghostscriptを使用すると、引数なしでプログラムを実行すると、同じ種類のエグゼクティブセッションが得られます。その後(yourfile)run
、エラーが発生した後もプロンプトが表示され、上記のように$errorを検査できます。
それでも問題が解決しない場合は、executive
2回実行してみてください。これにより、エラー処理のレベルが追加されます(stopped {handlerror} if
execスタックにもう1つ)。これは、より奇妙なエラーを探すのに役立つ場合があります。
段階的デバッガー
レベル2準拠のPostScriptインタープリターで実行する必要があるソースレベルの段階的デバッガーを利用できます。
TeX.SEのこの回答に示されているように、スタックトレースを生成するためにも使用できます。
EmacsにはPostScriptツールが含まれています。これには、現在選択されているテキストをポストスクリプトインタプリタに送信するためのツールが含まれています。また、同じインタプリタにコマンドを直接入力して、たとえば、オペランドスタックをクエリすることもできます。
ただし、これはあなたが探しているものではないかもしれません。なぜなら、あなたが喜んで作業するよりも使いにくいかもしれないからです。ただし、監視したいすべてのことに対して異なるバッファー、何かを実行するためのスクリプトとマクロなどを使用して正しく設定すると、必要なすべてのことを実行できます。よくわかりませんが、ネット上の他の場所に設定に役立つものがあるかもしれません。
編集:私がEmacsを使用してpostscriptをデバッグする主な方法は、次のことです。プログラムをステップスルーする方法として、プログラムのセグメントをファイルバッファーからインタープリターバッファーにコピーアンドペーストできます。また、コマンドを使用してその内容を出力するなど、オペランドスタックについての情報を提供するためにも使用できます。プログラムが他の環境を使用して実行されているときdup ==
に表示する方法を理解できなかったため、インタープリターバッファーに出力されるコード(など)にデバッグステートメントを追加することもできます。stdout
OS X 10.7.5 では、プレビューは爆撃時に詳細を提供しませんが、/usr/bin/pstopdf
stdout へのスタック ダンプを提供しpstack
ます。
pdf ファイルをプレビューで開いた場合、実行後にプレビューに戻すとpstopdf
、新しく作成された pdf ファイルのビューが更新されます。
ハイテクではありませんが、かなり高速に反復できます。