Linux內(nèi)核教程(1) - 道路千萬條酸员,調(diào)試最重要

Linux內(nèi)核教程(1) - 道路千萬條匈子,調(diào)試最重要

從信號量說起

大家可能都學(xué)過操作系統(tǒng)河胎,在操作系統(tǒng)課上,在進程同步互斥中虎敦,圖靈獎獲得者Dijkstra的信號量Semphone游岳。

Linux中當(dāng)然也提供了semphone的實現(xiàn)政敢,用做最普通的睡眠鎖。所謂睡眠鎖胚迫,意思是如果有一個任務(wù)試圖去獲取一個被占用的信號量時喷户,會被推到等待隊列中,然后讓其睡眠晌区。這樣CPU資源就可以用來處理別的事情摩骨,實現(xiàn)資源的合理利用。這與一直等待的自旋鎖形成鮮明的對比朗若。當(dāng)占有信號量的任務(wù)運行結(jié)束后恼五,會喚醒隊列里等待的任務(wù),這個信號量也會被喚醒的任務(wù)占有哭懈。
針對于P和V兩種原語的Linux實現(xiàn)是down和up兩個操作灾馒。還有支持被中斷的down_interruptible,可被殺的down_killable遣总,不等待的down_trylock睬罗,帶超時的down_timeout,考慮得非常周到旭斥。
不僅如此容达,信號量也是支持讀/寫信號量分離的。
一切看起來很美好垂券,不是么花盐?

我們看看semphone的作者在semphone.c的開頭是如何寫的:

2  /*
3   * Copyright (c) 2008 Intel Corporation
4   * Author: Matthew Wilcox <willy@linux.intel.com>
5   *
6   * This file implements counting semaphores.
7   * A counting semaphore may be acquired 'n' times before sleeping.
8   * See mutex.c for single-acquisition sleeping locks which enforce
9   * rules which allow code to be debugged more easily.
10   */

對于懶得看英文的同學(xué),我簡單翻譯一下算芯,如果只是獲取一次的鎖熙揍,建議改用mutex.h,這樣會使調(diào)試更容易届囚。

在Linux kernel中析砸,為了方便調(diào)試,基本上每種機制都有自己的調(diào)試宏,以CONFIG_DEBUG_*開頭。下面是我隨便搜的幾個:


config_debug

比如自旋鎖扰才,就有CONFIG_DEBUG_SPINLOCK,打開之后,會增加追蹤如下例:

3492  static inline void
3493  prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf)
3494  {
3495    /*
3496     * Since the runqueue lock will be released by the next
3497     * task (which is an invalid locking op but in the case
3498     * of the scheduler it's an obvious special-case), so we
3499     * do an early lockdep release here:
3500     */
3501    rq_unpin_lock(rq, rf);
3502    spin_release(&rq->lock.dep_map, _THIS_IP_);
3503  #ifdef CONFIG_DEBUG_SPINLOCK
3504    /* this is a valid case when another task releases the spinlock */
3505    rq->lock.owner = next;
3506  #endif
3507  }

很不幸蜡坊,semaphone不支持自動調(diào)試宏据忘,連受限的也做不到窍仰。
所以,信號量最好的場景是特別復(fù)雜的場景,比如跨內(nèi)核空間和用戶空間的復(fù)雜交互類的常空,反正調(diào)試也不靠這個攘残。
而對于內(nèi)核代碼中正常的使用病曾,應(yīng)該使用semaphone的受限版本mutex。
mutex是通過怎樣的自律來獲取自由的呢:

  • 任何時間寄疏,只能有一個任務(wù)持有mutex
  • 因為只有一個是牢,所以加鎖者必須負責(zé)給mutex解鎖
  • 因為要負責(zé)解鎖驳棱,所以持有mutex的進程不得退出
  • mutex不得用于中斷處理程序罚渐,也包括下半部谈息。不了解中斷和下半部原理的我們后面會介紹
  • mutex不能復(fù)制
  • mutex不能手動初始化
  • mutex只能初始化一次

加了這些自律之后凛剥,我們終于可以為mutex寫一些調(diào)試用的功能了侠仇。不像自旋鎖只是在處理上加了幾條語句,mutex專門設(shè)計了調(diào)試專用函數(shù)來做這些事情:

17  extern void debug_mutex_lock_common(struct mutex *lock,
18                      struct mutex_waiter *waiter);
19  extern void debug_mutex_wake_waiter(struct mutex *lock,
20                      struct mutex_waiter *waiter);
21  extern void debug_mutex_free_waiter(struct mutex_waiter *waiter);
22  extern void debug_mutex_add_waiter(struct mutex *lock,
23                     struct mutex_waiter *waiter,
24                     struct task_struct *task);
25  extern void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
26                  struct task_struct *task);
27  extern void debug_mutex_unlock(struct mutex *lock);
28  extern void debug_mutex_init(struct mutex *lock, const char *name,
29                   struct lock_class_key *key);

注:本文中的代碼取自kernel 5.9.10版犁享。

從信號量的例子我們就可以看到可調(diào)試性在內(nèi)核中的重要性余素。

同樣,有很多在內(nèi)核開發(fā)中被重點強調(diào)的內(nèi)容炊昆,其重要原因也是因為難以調(diào)試桨吊,比如棧溢出。
因為不像用戶空間的應(yīng)用程序容易退出凤巨,內(nèi)核本身是一直長期運行的视乐,這就導(dǎo)致內(nèi)核不得不面對內(nèi)存嚴(yán)重碎片化的情況,想要分配連續(xù)頁的內(nèi)存會越來越困難敢茁。而且用作棧的內(nèi)存也沒有辦法換出到輔助存儲中去佑淀,所以盡管棧溢出調(diào)試?yán)щy,也只能分配4k大小的棧卷要。所以就要求開發(fā)者以自律享受自由渣聚,盡量避免在棧上分量大的對象。一旦棧溢出了僧叉,產(chǎn)生的結(jié)果是難以預(yù)測的奕枝。

所以,我們把內(nèi)核的可調(diào)試性當(dāng)作第一要務(wù)來強調(diào)瓶堕。后面我們會調(diào)用各種手段來對內(nèi)核進行調(diào)試隘道,包括打日志,調(diào)試文件系統(tǒng),perf和ftrace等工具谭梗,甚至SystemTap和eBPF這樣的自動生成內(nèi)核模塊的腳本工具等忘晤,以及通過模擬器進行調(diào)試等各種手段。

編譯內(nèi)核

講了調(diào)試的重要性之后激捏,我們身體力行设塔,首先討論如何編譯內(nèi)核,如何在模擬器上跑起內(nèi)核远舅。
目前Linux的兩個最主要的應(yīng)用場景:一是跑在電腦上闰蛔,主要場景是給自己的電腦更換內(nèi)核;另一個是跑在嵌入式設(shè)備上图柏,比如手機等序六。

下載內(nèi)核

內(nèi)核源代碼地址可以在kernel.org上下載,比如我寫此文時最新的穩(wěn)定版是5.10.1蚤吹,我們就可以下載這個包:

wget -c https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.1.tar.xz

如果要下載源碼樹的話例诀,可以去clone kernel主線的代碼庫:

git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

在運行Linux的電腦上,我們可以通過包管理系統(tǒng)獲取到當(dāng)前使用的系統(tǒng)內(nèi)核的源代碼裁着。

比如在Ubuntu上繁涂,可以通過apt install linux-source來安裝源代碼:

root@iZ8vb39159pi4fttv8aaoyZ:/boot# apt search linux-source
Sorting... Done
Full Text Search... Done
linux-source/focal-updates,focal-updates,focal-security,focal-security,now 5.4.0.58.61 all [installed]
  Linux kernel source with Ubuntu patches

linux-source-5.4.0/focal-updates,focal-updates,focal-security,focal-security,now 5.4.0-58.64 all [installed,automatic]
  Linux kernel source for version 5.4.0 with Ubuntu patches

源代碼會下載到/usr/src目錄下。

編譯Ubuntu 20.04的內(nèi)核

下載之后跨算,我們將其解壓之后爆土,就可以進行編譯了。
安裝gcc, flex, bison, bc之類的常規(guī)操作就不多說了诸蚕,有遇到問題的請在評論區(qū)里提問步势。

編譯之前需要對內(nèi)核進行一些配置,比如調(diào)試信息等背犯。這些配置會寫在一個config文件中坏瘩。
以Ubuntu 20.04系統(tǒng)為例,在/boot目錄下可以看到一些config開頭的文件漠魏,比如config-5.4.0-58-generic倔矾,這些就是我們使用的Ubuntu系統(tǒng)的config文件。

這些配置項柱锹,以CONFIG_* = y這樣的形式來表示這個配置被支持哪自。而如果不支持的話,則把這個配置項用“#”注釋掉禁熏,并將=y改為is not set以利于理解壤巷。

比如我們上面討論的鎖的調(diào)試信息,在config文件中的描述如下:

#
# Lock Debugging (spinlocks, mutexes, etc...)
#
CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_PROVE_LOCKING is not set
# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_DEBUG_ATOMIC_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_WW_MUTEX_SELFTEST is not set
# end of Lock Debugging (spinlocks, mutexes, etc...)

我們以Ubuntu 20.04的源碼為例瞧毙,看看如何去編譯內(nèi)核胧华。
進入/usr/src/linux-source-5.4.0目錄寄症,我們會看到linux-source-5.4.0.tar.bz2,將其解壓矩动。
進入解壓后的目錄有巧,將/boot/config-5.4.0-58-generic文件復(fù)制過來。
然后執(zhí)行

make ./config-5.4.0-58-generic

成功后悲没,運行make menuconfig篮迎,在字符圖形界面下可以進行一些手動的配置:


kernel_config.png

配置好之后,保存到.config中檀训,最后執(zhí)行make -j4來進行編譯柑潦。j后面是編譯開啟的線程數(shù)。

編譯成功后峻凫,會看到類似于下面的輸出:

Setup is 16380 bytes (padded to 16384 bytes).
System is 8697 kB
CRC 1a8c27e4
Kernel: arch/x86/boot/bzImage is ready  (#1)

編好的kernel在arch/x86/boot/bzImage。

如果我們是想在模擬器上運行內(nèi)核的話览露,沒有Ubuntu給我準(zhǔn)備config荧琼。這也不怕,我們可以用x86_64的默認config差牛,在其基礎(chǔ)上進行修改命锄。首先我們需要設(shè)置下ARCH變量為x86_64,這樣不用寫路徑偏化,make就知道去哪里找x86_64_defconfig

export ARCH=x86_64
make x86_64_defconfig

然后make menuconfig和make不變脐恩。

成功后輸出如下:

Kernel: arch/x86/boot/bzImage is ready  (#2)

編譯ARM64內(nèi)核

x86_64的搞定了,換成別的架構(gòu)就是照方抓藥了侦讨。只不過需要裝交叉編譯的工具鏈驶冒。
在Ubuntu上,我們可以通過apt install gcc-aarch64-linux-gnu來安裝支持ARM64的工具鏈韵卤。
安裝好之后骗污,我們配置下CROSS_COMPILE環(huán)境變量:

export CROSS_COMPILE=aarch64-linux-gnu-

針對于arm64,只有一個defconfig沈条,設(shè)好ARCH之后就可以自動找到了:

export ARCH=arm64

ARCH后面的名字以arch下的子目錄名為準(zhǔn)需忿,目前kernel支持的架構(gòu)如下:

  • arc
  • arm64
  • csky
  • hexagon
  • m68k
  • mips
  • nios2
  • parisc
  • riscv
  • sh
  • um
  • x86_64
  • alpha
  • arm
  • c6x
  • h8300
  • ia64
  • microblaze
  • nds32
  • openrisc
  • powerpc
  • s390
  • sparc
  • x86
  • xtensa

我們執(zhí)行make defconfig

make defconfig

然后運行make -j8之類就可以了。

init程序

但是這樣編出來的內(nèi)核蜡歹,真的只是一個內(nèi)核屋厘,沒有任何shell之類的可以用。內(nèi)核啟動的最后月而,是要啟動一個init程序的汗洒,當(dāng)然我們也可以手寫一個。但是為了能有個shell景鼠,我們選擇用busybox的init.

我們?nèi)usybox.net去下載源碼:

wget -c https://busybox.net/downloads/busybox-1.32.0.tar.bz2

剛才編譯內(nèi)核時已經(jīng)設(shè)置好ARCH和CROSS_COMPILE了仲翎,正好busybox也能用到痹扇。
busybox沒那么多defconfig,上來就make menuconfig就好溯香。


busybox.png

我們只需要一個busybox程序鲫构,所以選擇Build static binary。
退出保存之后玫坛,執(zhí)行make -j4去編譯结笨。
最后,執(zhí)行make install湿镀,會安裝到_install目錄下炕吸。

準(zhǔn)備好了之后,我們需要給busybox的init準(zhǔn)備一個配置文件勉痴,一般是/etc/init.d/inittab赫模。這時候別說inittab了,我們連目錄還沒建呢蒸矛。

第一步:在_install目錄下創(chuàng)建etc,dev,mnt和etc/init.d/目錄:

mkdir etc
mkdir dev
mkdir mnt
mkdir -p etc/init.d/

mkdir加-p參數(shù)的意思是如果父目錄沒有創(chuàng)建瀑罗,則創(chuàng)建之。

第二步:創(chuàng)建inittab文件雏掠。
這個我們哪會寫斩祭,看busybox給我們的例子:

::sysinit:/etc/init.d/rcS
# /bin/sh invocations on selected ttys
#
# Note below that we prefix the shell commands with a "-" to indicate to the
# shell that it is supposed to be a login shell.  Normally this is handled by
# login, but since we are bypassing login in this case, BusyBox lets you do
# this yourself...
#
# Start an "askfirst" shell on the console (whatever that may be)
::askfirst:-/bin/sh
# Start an "askfirst" shell on /dev/tty2-4
tty2::askfirst:-/bin/sh
tty3::askfirst:-/bin/sh
tty4::askfirst:-/bin/sh

# /sbin/getty invocations for selected ttys
tty4::respawn:/sbin/getty 38400 tty5
tty5::respawn:/sbin/getty 38400 tty6

# Stuff to do when restarting the init process
::restart:/sbin/init

# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

我們把注釋刪一刪,tty也用不了這么多乡话,精簡一下:

::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

另外摧玫,我們不想用::respawn:-/sbin/getty或者login之類的登陸界面,直接進入系統(tǒng)绑青,所以加一條直接調(diào)shell: ::respawn:-/bin/sh诬像。
這個參考自busybox的examples/bootfloppy/etc下面的inittab

最后寫出來如下:

::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::respawn:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

寫完之后,我們欠Busybox一個啟動腳本/etc/init.d/rcS时迫。

第三步:在etc/init.d目錄下創(chuàng)建rcS文件颅停,如下:

mkdir -p /proc
mkdir -p /tmp
mkdir -p /sys
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

/proc是內(nèi)核向進程發(fā)送消息的機制。比如cat /proc/cpuinfo可以查看cpu運行信息掠拳,而cat /proc/meminfo是內(nèi)存信息癞揉。
/sys與/proc類似,也是內(nèi)核用于展示信息的虛擬文件系統(tǒng)溺欧,于2.5版引入喊熟,主要展示設(shè)備樹。
/tmp是臨時目錄
/mnt是掛載點
/dev/pts是通過ssh等遠程登陸時創(chuàng)建的控制臺設(shè)備文件

mdev是busybox提供的管理熱插拔的程序姐刁。

BusyBox v1.32.0 (2020-12-15 16:24:44 CST) multi-call binary.

Usage: mdev [-s] | [-df]

mdev -s is to be run during boot to scan /sys and populate /dev.
mdev -d[f]: daemon, listen on netlink.
    -f: stay in foreground.

Bare mdev is a kernel hotplug helper. To activate it:
    echo /sbin/mdev >/proc/sys/kernel/hotplug

如上面說明所示芥牌,-s用于啟動時掃描,激活命令我們也照抄聂使。

rcS寫好了之后需要通過chmod +x rcS賦給可執(zhí)行權(quán)限壁拉。

有同學(xué)問了谬俄,mount -a是掛載啥的?這是按照/etc/fstab來mount所有里面寫的文件系統(tǒng)的弃理,我們馬上就寫一個fstab溃论。
參照busybox-1.32.0/examples/bootfloppy/etc/init.d/rcS,mount -a調(diào)用fstab也是busybox的傳統(tǒng)操作痘昌。

第四步, 創(chuàng)建fstab文件
內(nèi)容如下:

proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0

到此為止钥勋,欠busybox init的連環(huán)債算是還清了,下面我們就以此文件系統(tǒng)去編譯內(nèi)核辆苔。

在qemu中運行

有了busybox的init程序算灸,我們重新編譯下內(nèi)核,在menuconfig中將剛才的_install目錄設(shè)置進去驻啤,在General配置的Init RAM filesystem中:


initramfs

將我們剛才準(zhǔn)備好的_install目錄的路徑設(shè)置進去就好菲驴。

配置好保存之后,make -j4開始編譯骑冗。

經(jīng)過一段歡快的編譯谢翎,生成Image:

...
  LD      vmlinux.o
  MODPOST vmlinux.symvers
  MODINFO modules.builtin.modinfo
  GEN     modules.builtin
  LD      .tmp_vmlinux.kallsyms1
  KSYMS   .tmp_vmlinux.kallsyms1.S
  AS      .tmp_vmlinux.kallsyms1.S
  LD      .tmp_vmlinux.kallsyms2
  KSYMS   .tmp_vmlinux.kallsyms2.S
  AS      .tmp_vmlinux.kallsyms2.S
  LD      vmlinux
  SORTTAB vmlinux
  SYSMAP  System.map
  MODPOST Module.symvers
  OBJCOPY arch/arm64/boot/Image
  GZIP    arch/arm64/boot/Image.gz

下面我們調(diào)用qemu來運行這個內(nèi)核,qemu可以通過apt來安裝沐旨。我們模擬4核A72,16G內(nèi)存:

qemu-system-aarch64 -machine virt -cpu cortex-a72 -machine type=virt -nographic -m 16384 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc console=ttyAMA0"

然后我們就可以登陸進我們的aarch64的Linux啦榨婆,我們可以uname看看磁携,是不是我們編的5.10.1:

/ # uname -a
Linux (none) 5.10.1 #4 SMP PREEMPT Wed Dec 16 18:19:47 CST 2020 aarch64 GNU/Linux

我們再看看cpuinfo:

/ # cat /proc/cpuinfo
processor   : 0
BogoMIPS    : 125.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd08
CPU revision    : 3

processor   : 1
BogoMIPS    : 125.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd08
CPU revision    : 3

processor   : 2
BogoMIPS    : 125.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd08
CPU revision    : 3

processor   : 3
BogoMIPS    : 125.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd08
CPU revision    : 3

最后的秘技是如何退出qemu,按Ctrl-a x良风,就可以退出了谊迄,顯示:

/ # QEMU: Terminated

恭喜,一個可玩的內(nèi)核已經(jīng)可以工作啦烟央。

懂源碼是根本

Linus反對在內(nèi)核里加入調(diào)試器也不是沒有道理统诺,調(diào)試器只是手段,我們也不能舍本逐末疑俭,有了方便的調(diào)試手段就不去鉆研原理和源碼了粮呢。
我們希望在解剖kernel的時候能讓大家有更豐富的視角,但是最近我們的目標(biāo)還是理解內(nèi)核的邏輯和代碼钞艇。
請大家跟我一起沉下心來啄寡,我們一步一步開始探索之旅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哩照,一起剝皮案震驚了整個濱河市挺物,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌飘弧,老刑警劉巖识藤,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砚著,死亡現(xiàn)場離奇詭異,居然都是意外死亡痴昧,警方通過查閱死者的電腦和手機稽穆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剪个,“玉大人秧骑,你說我怎么就攤上這事】勰遥” “怎么了乎折?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長侵歇。 經(jīng)常有香客問我骂澄,道長,這世上最難降的妖魔是什么惕虑? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任坟冲,我火速辦了婚禮,結(jié)果婚禮上溃蔫,老公的妹妹穿的比我還像新娘健提。我一直安慰自己,他們只是感情好伟叛,可當(dāng)我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布私痹。 她就那樣靜靜地躺著,像睡著了一般统刮。 火紅的嫁衣襯著肌膚如雪紊遵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天侥蒙,我揣著相機與錄音暗膜,去河邊找鬼。 笑死鞭衩,一個胖子當(dāng)著我的面吹牛学搜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播醋旦,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼恒水,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饲齐?” 一聲冷哼從身側(cè)響起钉凌,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捂人,沒想到半個月后御雕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矢沿,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年酸纲,在試婚紗的時候發(fā)現(xiàn)自己被綠了捣鲸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡闽坡,死狀恐怖栽惶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疾嗅,我是刑警寧澤外厂,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站代承,受9級特大地震影響汁蝶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜论悴,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一掖棉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膀估,春花似錦幔亥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捐寥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祖驱,已是汗流浹背握恳。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捺僻,地道東北人乡洼。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像匕坯,于是被迫代替她去往敵國和親束昵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容