调bug第一天

前几天有网友反馈, 说自己编译的Linux内核在D1开发板上运行一些应用程序的时候会报段错误。我当时繁忙, 就没详细了解这个事情。现在, 我需要用D1开发板进行科研活动, 因此需要解决这个问题, 否则在运行测试的时候很可能会崩溃。

我查看内核对段错误输出的信息后, 发现导致段错误的处理器异常代码为7, 根据RISC-V手册, 是Store/AMO access fault。这就很奇怪了, 居然不是page fault。经过cyy用objdump研究, 我们发现出错的指令是pthread库里面的一条amoswap.w原子操作指令。尝试自己编写一个最小的用pthread启动新线程的小程序, 确定其也可以触发同样的错误。

由于没想到其他办法, 就找来pthread源代码, 自己编译了一份, 方便后续再进行魔改。然后, 将上述小程序链接到自己编译的pthread以供测试。多次魔改pthread后, 我们发现普通的load或store指令不会导致上述异常, 而上述原子操作指令即使紧跟着一个store指令(这意味着CoW等机制已处理完毕), 也会产生异常。另外, 经过阅读pthread代码, 我发现最初产生异常的原子指令访问的目标是新线程的栈(上的TCB)。如果把普通load或store指令或原子指令放到新栈刚刚分配出来之后的程序点, 现象一致。

接下来, 继续考察用来分配新栈的函数。我发现, 在默认设置下, 栈的边界会有一个guard页面, 以便程序在栈溢出时能够有效地产生异常。为了实现guard机制, pthread首先用mmap()分配了一个没有权限(PROT_NONE)的新栈, 然后用mprotect()将新栈的guard以外的部分设置上了正确的权限。我无端猜测, 会不会是这个机制间接导致了上述报错。为了验证这个猜测, 我关闭了guard机制, 这样pthread一开始就会使用mmap()分配一个正确权限的栈。经过测试, 这样修改后, 原先出问题的原子操作指令确实不再产生异常了。

首先, 我们猜测是不是有什么TLB或缓存没有刷新, 从而导致TLB内容不正确, 接着导致上述原子操作指令产生异常。后来, 经过cyy花式刷TLB和缓存, 效果似乎不太明显, 指令仍然大概率会产生异常。

此外, 接下来还需要分析一下Linux内核mprotect()的代码, 由于时间较晚, 这个部分留到明天完成。

发表评论

注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)

本文链接:https://twd2.me/archives/16183QrCode