我正在尝试在本地镜像网站。但是,我在下载过程中的某个一致点遇到了分段错误,该错误位于与我的目标站点不同的域上(可能是由于--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
答案1
分段错误意味着程序(在本例中为 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
(“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”的名称发布了它。
我希望这些指示也能有所帮助!