2012-06-01 42 views
13

我正在編寫PHP Web應用程序的一部分(將用於高中錯誤發現比賽),用戶必須在給定的Java程序中找到錯誤。作爲其中的一部分,當Java程序執行時,我們想突出顯示代碼執行的Java程序源代碼行。爲此,我們需要的是已經執行的源代碼行號,即代碼路徑(或稱爲代碼覆蓋率?)。我們將使用行號突出顯示源文件中的行。已執行的java代碼的日誌行數

我們將使用PHP的shell-exec()來執行Java程序和獲取代碼路徑的工具(不管是什麼)。獲取代碼路徑行號的最簡單方法是什麼?

非常感謝!

這裏是一個圖片描述了我們想

enter image description here

回答

0

如果您使用-g選項編譯程序,做的printStackTrace(你可以得到一個行號),捕獲跟蹤輸出和從那裏提取亞麻布。

4

PHP將代碼交織在一起,這意味着每次運行程序時都會在源代碼上運行。隨着代碼被讀取(這使得行號輸出變得微不足道),這具有爆炸的好處;然而,在其他方面它往往是昂貴的,因爲你無法深度優化(或者做任何運行時錯誤檢查)。

Java compiles its code into a JVM assembly language called "bytecode."這意味着什麼是運行通常不能訪問(或甚至使用)源代碼。這就是說,有技巧。已編譯的Java類能夠添加「額外數據」,其中一個「額外數據元素」爲a line number table,這是一個索引,允許運行程序集的人在編譯器記錄時「查找」行號

這通常工作正常,考慮如下:編譯器通常不會標記每條指令,源代碼可能不可用,優化可能會使某些內部代碼塊無法以方便指向輸入的方式工作代碼文本。

代碼覆蓋工具如何「修復」這是因爲它們通常將大量的命令作爲日誌語句插入到代碼中(在程序集級別),該命令有效地用作允許工具確定通過代碼實際上是遵循的。然後通過行號表將其儘可能最佳地映射回來,然後用於突出顯示原始源文件中的行。

如果您想要更高分辨率的東西(可以處理線條的哪一部分被執行的東西),那麼您需要深入挖掘。最終,你甚至可以考慮編寫自己的編譯器(或編譯器擴展),它將存儲你自己的自定義行號表,以克服當前解決方案的缺點。

像投擲異常(如Shiven提到的)和解析行號的技巧確實有效;然而,他們污染你的代碼奇怪的例外處理的項目真的不是例外,只是爲了「獲取行號」。由於代碼混亂和異常運行時性能普遍較差,我傾向於避免這種解決方案(但它們確實有效)。

無論如何,希望這會給你一個看法,爲什麼它不總是像PHP一樣工作。

+0

如果你真的想要使用行號_without_ throwing異常,你可以編寫自己的'ClassLoader',這將能夠爲您提供一個工具來獲取行號表;但是,您可能還需要將自己的擴展寫入'Thread'以具有用於當前JVM字節碼指令的可用接口。這是可行的,因爲異常拋出對你來說已經是這樣了,但對於不同結構化日誌通常不必要的東西來說,這是很多工作。 –

+0

感謝您的支持!我理解編譯和解釋語言之間的區別,並知道獲取執行Java(或任何編譯語言)的行號並不是微不足道的。我已決定與Cobertura一起創建報告。我從來沒有使用過代碼覆蓋工具,所以這會花費我一些時間來弄清楚。請參閱此帖子下方的評論。幫助將不勝感激。非常感謝! – DanB91

1

看看Cobertura。它計算覆蓋率和類似的東西,如果它還沒有這樣做,那麼添加行號收集應該相對容易。 有一個非常hackish的嘗試做到這一點,但這是如此之慢,你可能無法在生產https://bitbucket.org/jowu/myriapod/wiki/Home

+0

我一直在看cobertura,它似乎做我想做的事情。我們想要的行號是在一個xml文件中,所以我們可以解析它。 但是我真的很難讓它通過命令行運行Java程序。那麼是爲了生成儀器的代碼路徑,運行然後報告?我嘗試這個,它會生成代碼路徑,但它顯示程序從未運行(所有行都是紅色的)。有什麼步驟來產生這個? – DanB91

+0

我只能將你指向cobertura文檔:http://cobertura.sourceforge.net/introduction.html。您可能需要重新編譯/重建您的項目,每次嘗試使用它時都會失敗,但除此之外,我從來沒有遇到過問題,並且您的問題沒有包含足夠的信息來幫助我弄清楚您可能會丟失什麼。 – Jochen

0

我從來沒有做過或見過這樣的事來使用它,但它似乎是一個有趣的問題。我的想法是使用the java debugger (jdb)來運行代碼,而不僅僅是java命令。

您可以逐行執行代碼(通過jdb中的step命令),並且每次執行其行號時都會吐出。這需要PHP方面的一點幫助(它必須解析行號以及執行下一步命令),但行號在那裏。這是一個非常基本的Java程序的示例輸出。

的Java(TestClass.java)

public class TestClass { 
    public static void main(String[] args) { 
     System.out.println("foo"); 
     System.out.println("bar"); 
    } 
} 

加多寶(加多寶的TestClass運行javac TestClass.java後)

Initializing jdb ... 
> stop at TestClass:3 
Deferring breakpoint TestClass:3. 
It will be set after the class is loaded. 
> run 
run TestClass 
Set uncaught java.lang.Throwable 
Set deferred uncaught java.lang.Throwable 
> 
VM Started: Set deferred breakpoint TestClass:3 

Breakpoint hit: "thread=main", TestClass.main(), line=3 bci=0 
3   System.out.println("foo"); 

main[1] step 
> foo 

Step completed: "thread=main", TestClass.main(), line=4 bci=8 
4   System.out.println("bar"); 

main[1] step 
> bar 

Step completed: "thread=main", TestClass.main(), line=5 bci=16 
5  } 

main[1] step 
> 
The application exited 
0

嘗試參照此鏈接JVMDI

可以嘗試訪問程序計數器的值然後映射它到lineNumberTable上。 或 我認爲JVMDI有一個方法可以訪問正在執行的代碼的行號。我不確定後者,請參閱上面的鏈接,並希望它有幫助。