13小时在Raspberry Pi上的.NET Core中调试分段错误,解决方案是...

Debugging is a satisfying and special kind of hell. You really have to live it to understand it. When you're deep into it you never know when it'll be done. When you do finally escape it's almost always a DOH! moment.

调试是一种令人满意的特殊方式。 您真的必须活着才能理解它。 当您深入研究它时,您将永远不知道它何时完成。 当您最终逃脱时,几乎总是DOH! 时刻。

I spent an entire day debugging an issue and the solution ended up being a checkbox.

我花了一整天的时间调试问题,解决方案最终变成了一个复选框。

NOTE: If you get a third of the way through this blog post and already figured it out, well, poop on you. Where were you after lunch WHEN I NEEDED YOU?

注意:如果您通过本博客文章了解了三分之一,并且已经弄清楚了,那就大便吧。 午饭后你在哪里?

I wanted to use a Raspberry Pi in a tech talk I'm doing tomorrow at a conference. I was going to show .NET Core 2.0 and ASP.NET running on a Raspberry Pi so I figured I'd start with Hello World. How hard could it be?

我想在明天的会议上进行技术演讲时使用Raspberry Pi。 我打算展示在Raspberry Pi上运行的.NET Core 2.0和ASP.NET,所以我认为我将从Hello World开始。 它能有多难?

You'll write and build a .NET app on Windows or Mac, then publish it to the Raspberry Pi. I'm using a preview build of the .NET Core 2.0 command line and SDK (CLI) I got from here.

您将在Windows或Mac上编写并构建.NET应用程序,然后将其发布到Raspberry Pi。 我正在使用从此处获得的.NET Core 2.0命令行和SDK(CLI)的预览版

C:\raspberrypi> dotnet new console
C:\raspberrypi> dotnet run
Hello World!
C:\raspberrypi> dotnet publish -r linux-arm
Microsoft Build Engine version for .NET Core

raspberrypi1 -> C:\raspberrypi\bin\Debug\netcoreapp2.0\linux-arm\raspberrypi.dll
raspberrypi1 -> C:\raspberrypi\bin\Debug\netcoreapp2.0\linux-arm\publish\

Notice the simplified publish. You'll get a folder for linux-arm in this example, but could also publish osx-x64, etc. You'll want to take the files from the publish folder (not the folder above it) and move them to the Raspberry Pi. This is a self-contained application that targets ARM on Linux so after the prerequisites that's all you need.

注意简化的发布。 在此示例中,您将获得linux-arm的文件夹,但也可以发布osx-x64等。您需要从publish文件夹(而不是其上方的文件夹)中获取文件,并将其移至Raspberry Pi 。 这是一个针对Linux上的ARM的自包含应用程序,因此您仅需满足先决条件即可。

I grabbed a mini-SD card, headed over to https://www.raspberrypi.org/downloads/ and downloaded the latest Raspbian image. I used etcher.io - a lovely image burner for Windows, Mac, or Linux - and wrote the image to the SD Card. I booted up and got ready to install some prereqs. I'm only 15 min in at this point. Setting up a Raspberry Pi 2 or Raspberry Pi 3 is VERY smooth these days.

我抓住了一个微型SD卡,转到https://www.raspberrypi.org/downloads/,并下载了最新的Raspbian映像。 我使用etcher.io (适用于Windows,Mac或Linux的漂亮图像刻录机)并将图像写入SD卡。 我启动并准备安装一些先决条件。 目前我只有15分钟的路程。 如今,设置Raspberry Pi 2或Raspberry Pi 3十分顺利。

Here's the prereqs for .NET Core 2 on Ubuntu or Debian/Raspbian. Install them from the terminal, natch.

这是Ubuntu或Debian / Raspbian上.NET Core 2的先决条件。 从终端安装它们,natch。

sudo apt-get install libc6 libcurl3 libgcc1 libgssapi-krb5-2 libicu-dev liblttng-ust0 libssl-dev libstdc++6 libunwind8 libuuid1 zlib1g

I also added an FTP server and ran vncserver, so I'd have a few ways to talk to the Raspberry Pi. Yes, I could also SSH in but I have a spare monitor, and with that monitor plus VNC I didn't see a need.

我还添加了一个FTP服务器并运行了vncserver,因此我可以通过几种方法与Raspberry Pi进行通信。 是的,我也可以使用SSH进行登录,但是我有一个备用监视器,并且有了该监视器和VNC,我认为没有必要。

sudo apt-get pure-ftpd
vncserver

Then I fire up Filezilla - my preferred FTP client - and FTP the publish output folder from my dotnet publish above. I put the files in a folder off my ~\Desktop.

然后,我启动Filezilla (我的首选FTP客户端),并通过FTP从上面发布的dotnet中发布发布输出文件夹。 我将文件放在〜\ Desktop的文件夹中。

FTPing files

Then from a terminal I

然后从终端我

pi@raspberrypi:~/Desktop/helloworld $ chmod +x raspberrypi

(or whatever the name of your published "exe" is. It'll be the name of your source folder/project with no extension. As this is a self-contained published app, again, all the .NET Core runtime stuff is in the same folder with the app.

(或您发布的“ exe”的任何名称。它将是您的源文件夹/项目的名称,没有扩展名。由于这是一个自包含的已发布应用程序,因此,所有.NET Core运行时内容都位于与应用程序相同的文件夹。

pi@raspberrypi:~/Desktop/helloworld $ ./raspberrypi 
Segmentation fault

The crash was instant...not a pause and a crash, but it showed up as soon as I pressed enter. Shoot.

崩溃是立即发生的……不是停顿和崩溃,而是在我按Enter键后立即出现。 射击。

I ran "strace ./raspberrypi" and got this output. I figured maybe I missed one of the prerequisite libraries, and I just needed to see which one and apt-get it. I can see the ld.so.nohwcap error, but that's a historical Debian-ism and more of a warning than a fatal.

我运行了“ strace ./raspberrypi”并获得了此输出。 我想也许我错过了一个先决条件库,而我只需要看一下哪个库就可以了。 我可以看到ld.so.nohwcap错误,但这是历史性的Debian主义,更多的是警告,而不是致命的警告

strace on a bad exe in Linux

I used to be able to read straces 20 years ago but much like my Spanish, my skills are only good at Chipotle. I can see it just getting started loading libraries, seeking around in them, checking file status,  mapping files to memory, setting memory protection, then it all falls apart. Perhaps we tried to do something inappropriate with some memory that just got protected? We are dereferencing a null pointer.

我20年前曾经能阅读海峡,但是和我的西班牙语一样,我的技能只擅长Chipotle。 我可以看到它只是开始加载库,在其中查找,检查文件状态,将文件映射到内存,设置内存保护,然后一切都崩溃了。 也许我们试图对刚刚受保护的内存做一些不合适的事情? 我们正在取消引用空指针。

Maybe you can read this and you already know what is going to happen! I did not.

也许您可以阅读此书,并且您已经知道会发生什么! 我没有。

I run it under gdb:

我在gdb下运行它:

pi@raspberrypi:~/Desktop/WTFISTHISCRAP $ gdb ./raspberrypi 
GNU gdb (Raspbian 7.7.1+dfsg-5+rpi1) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
This GDB was configured as "arm-linux-gnueabihf".
"/home/pi/Desktop/helloworldWRONG/./raspberrypi1": not in executable format: File truncated
(gdb)

Ok, sick files?

好,病态档案?

I called Peter Marcu from the .NET team and we chatted about how he got it working and compared notes.

我从.NET团队打电话给Peter Marcu,我们聊了聊他是如何工作的,并比较了笔记。

I was using a Raspberry Pi 2, he a Pi 3. Ok, I'll try a 3. 30 minutes later, new SD card, new burn, new boot, pre-reqs, build, FTP, run, SAME RESULT - segfault.

我使用的是Raspberry Pi 2,他使用的是Pi3。好的,我会尝试3. 3分钟。新的SD卡,新的刻录,新的启动,先决条件,构建,FTP,运行,相同的结果-segfault 。

Weird.

奇怪的。

Maybe corruption? Here's a thread about Corrupted Files on Raspbian Jesse 2017-07-05! That's the version I have. OK, I'll try the build of Raspbian from a week before.

也许是腐败? 这是有关Raspbian Jesse上损坏的文件的主题2017-07-05 ! 那是我的版本。 好的,我将在一周前尝试构建Raspbian。

30 minutes later, burn another SD card, new boot, pre-reqs, build, FTP, run, SAME RESULT - segfault.

30分钟后,刻录另一个SD卡,新启动,先决条件,构建,FTP,运行,相同结果-segfault。

BUT IT WORKS ON PETER'S MACHINE.

但是可以在PETER的机器上工作。

Weird.

奇怪的。

Maybe a bad nuget.config? No.

也许是坏的nuget.config吗? 没有。

Bad daily .NET build? No.

每天的.NET版本不好? 没有。

BUT IT WORKS ON PETER'S MACHINE.

但是可以在PETER的机器上工作。

Ok, I'll try Ubuntu Mate for Raspberry Pi. TOTALLY different OS.

好的,我将为Raspberry Pi尝试Ubuntu Mate。 完全不同的操作系统。

30 minutes later, burn another SD card, new boot, pre-reqs, build, FTP, run, SAME RESULT - segfault.

30分钟后,刻录另一个SD卡,新启动,先决条件,构建,FTP,运行,相同结果-segfault。

What's the common thread here? Ok, I'll try from another Windows machine.

这里的共同点是什么? 好的,我将在另一台Windows计算机上尝试。

SAME RESULT - segfault.

结果相同-段错误。

I call Peter back and we figure it's gotta be prereqs...but the strace doesn't show we're even trying to load any interesting libraries. We fail FAST.

我给Peter打回电话,我们认为这必须是先决条件...但是strace并不表明我们甚至试图加载任何有趣的库。 我们失败了。

Ok, let's get serious.

好吧,让我们认真一点。

We both have Raspberry Pi 3s. Check.

我们都有Raspberry Pi 3s。 检查一下

What kind of SD card does he have? Sandisk? Ok,  I'll use Sandisk. But disk corruption makes no sense at that level...because the OS booted!

他拥有哪种SD卡? Sandisk? 好的,我将使用Sandisk。 但是在该级别上磁盘损坏没有任何意义……因为操作系统已启动!

What did he burn with? He used Win32diskimager and I used Etcher. Fine, I'll bite.

他烧了什么? 他使用Win32diskimager,而我使用Etcher。 好我会咬

30 minutes later, burn another SD card, new boot, pre-reqs, build, FTP, run, SAME RESULT - segfault.

30分钟后,刻录另一个SD卡,新启动,先决条件,构建,FTP,运行,相同结果-segfault。

He sends me HIS build of a HelloWorld and I FTP it over to the Pi. SAME RESULT - segfault.

他向我发送了HelloWorld的HIS版本,并通过FTP将其发送给Pi。 结果相同-段错误。

Peter is freaking out. I'm deeply unhappy and considering quitting my job. My kids are going to sleep because it's late.

彼得吓坏了。 我很不高兴,正在考虑辞职。 我的孩子要睡了,因为已经晚了。

I ask him what he's FTPing with, and he says WinSCP. I use FileZilla, ok, I'll try WinSCP.

我问他他用FTP传输什么,他说WinSCP。 我使用FileZilla,好的,我将尝试WinSCP

WinSCP's New Session dialog starts here:

WinSCP的“新建会话”对话框从此处开始:

SFTP is Default

I say, WAIT. Are you using SFTP or FTP? Peter says he's using SFTP so I turn on SSH on the Raspberry Pi and SFTP into it with WinSCP and copy over my Hello World.

我说,等等。 您使用的是SFTP还是FTP? 彼得说他正在使用SFTP,所以我在Raspberry Pi上打开SSH,并使用WinSCP将SFTP插入其中,并通过我的Hello World复制。

IT FREAKING WORKS. IMMEDIATELY.

它非常出色。 立即。

Hello World on a Raspberry Pi

BUT WHY.

但为什么。

I make a folder called Good and a folder called BAD. I copy with FileZilla to BAD and with WinSCP to GOOD. Then I run a compare. Maybe some part of .NET Core got corrupted? Maybe a supporting native library?

我制作了一个名为Good的文件夹和一个名为BAD的文件夹。 我将FileZilla复制到BAD,将WinSCP复制到GOOD。 然后我进行比较。 也许.NET Core的某些部分损坏了? 也许是支持本机的图书馆?

pi@raspberrypi:~/Desktop $ diff --brief -r helloworld/ helloworldWRONG/
Files helloworld/raspberrypi1 and helloworldWRONG/raspberrypi1 differ

Wait, WHAT? The executable are different? One is 67,684 bytes and the bad one is 69,632 bytes.

等等,什么? 可执行文件是否不同? 一个是67,684字节,坏的是69,632字节。

Time for a  visual compare.

进行视觉比较的时间。

All the ODs are gone

At this point I saw it IMMEDIATELY.

在这一点上,我立即看到了它。

0D is CR (13) and 0A is LF (10). I know this because I'm old and I've written printer drivers for printers that had both carriages and lines to feed. Why do YOU know this? Likely because you've transferred files between Unix and Windows once or thrice, perhaps with FTP or Git.

0D为CR(13),0A为LF(10)。 我知道这一点是因为我年纪大了,而且我已经为同时具有笔架和送纸线的打印机编写了打印机驱动程序。 你为什么知道这个? 可能是因为您一次或三次在Unix和Windows之间传输文件,也许使用FTP或Git。

All the CRs are gone. From my binary file.

所有CR都消失了。 从我的二进制文件。

Why?

为什么?

I went straight to settings in FileZilla:

我直接进入FileZilla中的设置:

Treat files without extensions as ASCII files

See it?

看见?

Treat files without extensions as ASCII files

将无扩展名的文件视为ASCII文件

That's the default in FileZilla. To change files that are just chilling, minding their own business, as ASCII, and then just randomly strip out carriage returns. What could go wrong? And it doesn't even look for CR LF pairs! No, it just looks for CRs and strips them. Classy.

这是FileZilla中的默认设置。 要更改令人不寒而栗的文件,请注意自己的业务(如ASCII),然后随机除去回车符。 可能出什么问题了? 而且它甚至都不寻找CR LF对! 不,它只是查找CR并剥离它们。 优雅

In retrospect I should have used known this, but it wasn't even the switch to SFTP, it was the switch to an FTP program with different defaults.

回想起来,我应该使用已知的方法,但是它甚至没有切换到SFTP,而是切换到了具有不同默认值的FTP程序。

This bug/issue whatever burned my whole Monday. But, it'll never burn another Monday, Dear Reader, because I've seen it before now.

这个虫子/问题烧毁了我整个星期一。 但是,亲爱的读者,它再也不会燃烧了,因为我之前已经看过它。

FAIL FAST FAIL OFTEN my friends!

失败快速失败我的朋友们!

Why does experience matter? It means I've failed a lot in the past and it's super useful if I remember those bugs because then next time this happens it'll only burn a few minutes rather than a day.

为什么经验很重要? 这意味着我过去已经失败了很多次,如果我记得那些错误,那将非常有用,因为下次发生这种情况时,它只会消耗几分钟而不是一天。

Go forth and fail a lot, my loves.

亲爱的,继续前进,失败很多。

Oh, and FTP sucks.

哦,FTP很烂。

Sponsor: Thanks to Redgate! A third of teams don’t version control their database. Connect your database to your version control system with SQL Source Control and find out who made changes, what they did, and why. Learn more

赞助商:感谢Redgate ! 三分之一的团队没有版本控制他们的数据库。 使用SQL Source Control将数据库连接到版本控制系统,并找出谁进行了更改,所做的更改以及原因。 学到更多

翻译自: https://www.hanselman.com/blog/13-hours-debugging-a-segmentation-fault-in-net-core-on-raspberry-pi-and-the-solution-was

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值