Wget segfault—我怎麼知道是哪個網站造成的?
我正在嘗試在本地鏡像網站。但是,我在下載的某個一致點上遇到了分段錯誤,在與我所針對的站點不同的域上(可能是由於
--page-requisites
)。2018-04-09 04:58:32 (346 KB/s) - './not-website.com/2017/06/28/xyz/index.html' saved [145810] 29247 Segmentation Fault (core dumped) wget --directory-prefix="${DL_ROOT}" --recursive --page-requisites --span-hosts --tries="${TRIES_NUM}" --timeout="${TIMEOUT_NUM}" --reject="*.tar" --convert-links --adjust-extension --continue --no-check-certificate "http://website.com/"
因此,我假設分段錯誤是由於 wget 嘗試下載特定網站但失敗所致。
但是,錯誤消息似乎沒有告訴我 wget 失敗的地址。它只告訴我最後一次成功下載。我怎樣才能弄清楚 wget 在哪裡/為什麼會因為這個段錯誤而失敗?
core
錯誤似乎引用了一個 55M文件(core dumped)
,但它不是純文字。那裡有我需要的資訊嗎?如何提取?我已經在發行版(Solaris、Debian、Raspbian)上對此進行了測試,並且這個段錯誤是一致的,並且總是在相同的地址之後(
not-website.com/...
在上面的錯誤消息中)。我正在使用命令:
$ wget \ --directory-prefix="${DL_ROOT}" \ --recursive \ --page-requisites \ --span-hosts \ --tries="${TRIES_NUM}" \ --timeout="${TIMEOUT_NUM}" \ --reject="*.tar" \ --convert-links \ --adjust-extension \ --continue \ --no-check-certificate \ "http://website.com/"
附加資訊
這是一個很大的網站,有相當多的媒體。在故障點,下載的目錄大小約為 252M。
測試:
GNU Wget 1.18 built on solaris2.10. -cares +digest -gpgme +https +ipv6 -iri +large-file -metalink -nls +ntlm +opie -psl +ssl/openssl
和
GNU Wget 1.18 built on linux-gnu. -cares +digest -gpgme +https +ipv6 +iri +large-file -metalink +nls +ntlm +opie +psl +ssl/gnutls
和
GNU Wget 1.16 built on linux-gnueabihf. +digest +https +ipv6 +iri +large-file +nls +ntlm +opie +psl +ssl/gnutls
分段錯誤意味著程序,在這種情況下,wget,試圖訪問一個無效的記憶體地址,因此被核心終止。這通常是由於程序錯誤而發生的,因此雖然它很可能是由特定網站或網頁觸發的(考慮到您似乎能夠在多個平台上同時在同一點上非常一致地重現它),但它您仍然可能已經暴露了 wget 本身的錯誤。
為了找到在 wget 中發生分段錯誤的位置,您可以使用
gdb
程序(GNU 調試器)在 wget 崩潰時獲取它的堆棧跟踪,因為您有一個core
文件,所以這是可能的。(核心轉儲是正在執行的程序由於無效操作(例如分段錯誤)而終止時的映像副本。)為此,請使用以下命令:
$ gdb wget core
它將在
wget
二進製文件(從路徑)上啟動調試器並將core
文件(在目前目錄中)恢復為正在執行的程序的映像。
gdb
然後將列印有關該程序的一些資訊並給您一個提示:$ gdb wget core GNU gdb (GDB) 7.9 Copyright (C) 2015 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> ... Core was generated by `wget --directory-prefix=... --recursive --page-requisites --span-hosts --tries=... --timeout=... --reject=*.tar --convert-links --adjust-extension --continue --no-check-certificate http://website.com/'. Program terminated with signal SIGSEGV, Segmentation Fault. (gdb) _
此時,您可以使用命令
bt
(“backtrace”的縮寫)向您顯示程序崩潰時正在執行的操作。這通常是開始尋找錯誤的好地方。例如,您可能會看到如下內容:
(gdb) bt #0 0x00007f5371206363 in __select_nocancel () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x0000559e5acbf21c in select_fd () #2 0x0000559e5acf0bde in wgnutls_poll () #3 0x0000559e5acbf3a2 in poll_internal () #4 0x0000559e5acbf6ed in fd_peek () #5 0x0000559e5ace423d in fd_read_hunk () #6 0x0000559e5acd5ef9 in gethttp () #7 0x0000559e5acd9b26 in http_loop () #8 0x0000559e5ace53c8 in retrieve_url () #9 0x0000559e5ace273b in retrieve_tree () #10 0x0000559e5acbe67d in main ()
然後您可以
gdb
使用q
(for “quit”) 命令退出:(gdb) q
如果您安裝了“調試符號”,通常會很有幫助。這些是編譯器生成的用於調試二進製文件的資訊,通常會為安裝在系統上的二進製文件而剝離,因此它們的大小更小。該資訊可以保存到另一個位置(通常在 下
/usr/lib/debug
),gdb
在嘗試調試二進製文件時可以找到該位置。有了這些資訊,您的回溯通常會附加更多資訊,例如所有內部函式的名稱。
在 Debian 上,您可以使用以下命令安裝 wget 的調試資訊:
$ sudo apt-get install wget-dbgsym
您可能還想為 glibc 安裝調試符號:
$ sudo apt-get install libc6-amd64-dbgsym
話雖如此,在您開始了解 wget 崩潰的原因之前,您可能想嘗試最新版本的 wget,它似乎是 1.9.4 版本,您可以在此處下載。那是一個原始碼包,因此您可能需要從原始碼建構以使其在您的系統中工作。
這是因為分段錯誤通常是由錯誤引起的,而且很可能這個錯誤已經在 wget 中修復並且修復存在於最新版本中。
如果您在最新版本中遇到相同的問題,請考慮獲取核心文件並使用 gdb 獲取回溯,然後將錯誤報告給 wget 維護人員,以便他們有機會解決它。
如果它已在最新的 wget 1.9.4 上修復,但它存在於您正在使用的 Debian 版本中,請考慮將此報告給 Debian,以便他們有機會將更新檔反向移植到他們的 wget 版本。
還有一個名為wget2的新項目,看起來他們正試圖用新的程式碼庫替換 wget。您可能想檢查那個是否有效……最近 Debian 似乎以“wget2”的名義發布了它。
我希望這些指示也有幫助!