Linux

Wget segfault—我怎麼知道是哪個網站造成的?

  • April 9, 2018

我正在嘗試在本地鏡像網站。但是,我在下載的某個一致點上遇到了分段錯誤,在與我所針對的站點不同的域上(可能是由於--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”的名義發布了它。

我希望這些指示也有幫助!

引用自:https://unix.stackexchange.com/questions/436420