> For the complete documentation index, see [llms.txt](https://hansimov.gitbook.io/csapp/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hansimov.gitbook.io/csapp/labs/bomb-lab/readme-jiang-shi-ban.md).

# README（讲师版）

> CS:APP Bomb Lab
>
> 给讲师的指导
>
> Copyright (c) 2003-2016, R. Bryant and D. O'Hallaron

此目录包含你用于构建和运行 CS:APP Bomb Lab 的文件。Bomb Lab 教授学生机器级程序的原理，以及一般的调试器和逆向工程技能。

## 1. 概述

### 1.1 二进制炸弹

一个“二进制炸弹”是由六个 “阶段” 组成的 Linux 可执行 C 程序，每个阶段都要求学生在 stdin 上输入一个特定的字符串。如果学生输入预期的字符串，则该阶段为 “拆除”，否则炸弹则打印 “BOOM!!!” 表示“爆炸”。学生们的目标是拆除尽可能多的阶段。

### 1.2 解决二进制炸弹

为了拆除炸弹，学生必须使用一个调试器，通常是 gdb 或 ddd，在每个阶段反汇编二进制文件，并对机器码单步调试。想法是让学生理解每个汇编语句的作用，然后使用这些知识来推断要拆除的字符串。学生通过拆除阶段获得分数，每次爆炸都会损失分数（由讲师配置，但通常为 1/2 分）。因此，他们将很快学会在每个阶段和引爆炸弹的函数之前设置断点。这是一个很好的教训，迫使他们学会使用调试器。

### 1.3 自动评分服务

我们创建了一个独立的用户级自动评分服务，为你处理 Bomb Lab 的所有方面：学生从服务器下载他们的炸弹。当学生们在研究他们的炸弹时，每一次爆炸和拆除都会传回到服务器上，在服务器上，每个炸弹的当前结果都会显示在一个网络“记分板”上。没有明显的提交，实验会自己评分。

自动评分服务由四个用户级程序组成，这些程序运行在 ./bomblab 主目录中：

* 请求服务器（bomblab-requestd.pl）。学生下载炸弹并显示记分牌，方法是将浏览器指向一个名为“请求服务器”的简单 HTTP 服务器。请求服务器生成炸弹，将其存档在 tar 文件中，然后将生成的 tar 文件上传回浏览器，在浏览器中可以将其保存在磁盘上并解压。请求服务器还为讲师创建炸弹及其解答的副本。
* 结果服务器（bomblab-resultd.pl）。每次学生拆除炸弹阶段或引起爆炸时，炸弹都会向 HTTP “结果服务器”发送一条名为 “自动结果字符串” 的简短 HTTP 消息，该服务器只是将自动结果字符串附加到“记分板日志文件”中。
* 报告守护**进程**（bomblab-reportd.pl）。“报告守护进程”定期扫描记分板日志文件。报表守护进程查找每个学生为每个阶段提交的最新的拆除字符串，并将这些字符串应用于学生炸弹的本地副本，来验证这些字符串。然后它会更新 HTML 记分板，该记分板汇总了每枚炸弹的当前爆炸和拆除次数，按累计点数排序。
* 主守护进程（bomblab.pl）. “主守护进程”启动并保护请求服务器、结果服务器和报表守护进程，确保这些进程（以及它本身）在任何时间点都在运行。如果其中一个进程由于某种原因死亡，主守护进程会检测到并自动重新启动它。主守护进程是您实际需要运行的唯一程序。

## 2. 文件

./bomblab 目录包含下列文件：

| 文件名                     | 说明                          |
| ----------------------- | --------------------------- |
| Makefile                | 开始/停止实验和清除文件                |
| bomblab.pl\*            | 主守护进程，守护其他服务器和守护进程          |
| Bomblab.pm              | Bomb Lab 配置文件               |
| bomblab-reportd.pl\*    | 报告守护进程，持续更新记分板              |
| bomblab-requestd.pl\*   | 请求服务器，将炸弹提供给学生              |
| bomblab-resultd.pl\*    | 结果服务器，从炸弹得到自动结果字符串          |
| bomblab-scoreboard.html | 实时网络记分板                     |
| bomblab-update.pl\*     | 帮助 bomblab-reportd.pl 更新记分板 |
| bombs/                  | 包含发送给每个学生的炸弹                |
| log-status.txt          | 状态日志，来自不同服务器和守护进程的消息        |
| log.txt                 | 自动结果记分板日志，接受自炸弹             |
| makebomb.pl\*           | 帮助脚本，用于制作炸弹                 |
| scores.txt              | 合计每个学生的当前记分板分数              |
| src/                    | 炸弹源文件                       |
| writeup/                | Bomb Lab 的 LaTeX 报告样例       |

## 3. 炸弹术语

* **LabID**：该实验的每个实例（用品）都由唯一的名称标识，例如 “f12” 或 “s13”，由讲师选择。和当前 LabID 不同的炸弹的爆炸和拆除动作将被忽略。LabID 不能有空格。
* **BombID**：实验给定实例中的每个炸弹都有唯一的非负整数，称为 “bombID”。
* **通知炸弹**（Notifying Bomb）：一个炸弹可以用一个 NOTIFY 选项编译，当学生每次爆炸或拆除一个阶段时，炸弹都会发送一条消息。这种炸弹被称为“通知炸弹”。
* **安静炸弹**（Quiet Bomb）：如果使用 NONOTIFY 选项编译，则炸弹在爆炸或拆除时不会发送任何消息。这种炸弹被称为“安静炸弹”。

我们还会发现区分定制炸弹和普通炸弹很有帮助：

* **定制炸弹**（Custom Bomb）：“定制炸弹”的 BombID > 0，与特定学生关联，可以是通知的或安静的。定制的通知炸弹被限制在讲师确定的一组特定的 Linux 主机上运行。另一方面，定制的安静炸弹可以在任何 Linux 主机上运行。
* **通用炸弹**（Generic Bomb）：一个“通用炸弹”的 BombID = 0，与任何特定的学生没有关联，是安静的，因此可以在任何主机上运行。

## 4. 提供炸弹实验

Bomb Lab 有两种基础版本：在“在线”版本中，讲师使用自动评分服务向每个学生分发定制的通知炸弹，并在实时记分板上自动跟踪他们的进度。在“离线”版本中，讲师手动制作、分发和评分学生炸弹，而不使用自动评分服务。

虽然这两个版本都给了学生丰富的经验，我们推荐在线版本。对于学生来说，这显然是最吸引人和最有趣的，也是老师最容易评分的。但是，它要求你不停地运行自动评分服务，因为在实验期间，讲义、评分和报告都是连续不断地进行的。我们已经使这项服务非常容易运行，但是一些讲师可能不喜欢这个要求，而是选择离线版本。

以下是提供两个版本的实验的说明。

### 4.1 创建一个 Bomb Lab 目录

确定要创建 Bomb Lab 目录（**./bomblab**）的通用 Linux 机器（**$SERVER\_NAME**），如果提供联机版本，请运行自动评分服务。你只需在这台机器上有一个用户帐户，不需要 root 权限。 Bomb Lab 的每个实例启动时，都伴随着 $SERVER\_NAME 上一个全新的 **./bomblab** 目录。例如：

```c
linux> tar xvf bomblab.tar
linux> cd bomblab   
linux> make cleanallfiles
```

### 4.2 配置 Bomb Lab

通过编辑以下文件配置 Bomb Lab：

* **./Bomblab.pm：**&#x8FD9;是主配置文件。你只需修改或检查此文件第 1 节的几个变量。每个变量前面都有一个描述性注释。如果提供离线版本，那么可以忽略其中的大多数设置。

如果你提供在线版本，则还需要编辑以下文件：

* **./src/config.h：**&#x6B64;文件列出了允许运行炸弹的主机的域名。确保你正确地更新了这个，否则你和你的学生将无法运行你的炸弹。

### 4.3 更新实验报告

更新完配置文件后，请根据你的环境，修改 **writeup/bomblab.tex** 中的 LaTeX 报告。然后在 **./writeup** 目录中键入以下内容：

```c
unix> make clean
unix> make 
```

这会创建报告的 ps 和 pdf 版本。

### 4.4 运行在线 Bomb Lab

#### 4.4.1 简短版本

来自 ./bomblab 目录：

（1）重置 Bomb Lab，键入：

```c
linux> make cleanallfiles
```

（2）开启自动评分服务，键入：

```c
linux> make start
```

（3）停止自动评分服务，键入：

```
linux> make stop
```

你可以随时开启和停止自动评分服务，这不会丢失任何信息。如果不确定服务状态，输入 “**make stop; make start**” 可以让一切都进入稳定状态。

但是，重置实验室删除所有旧的炸弹、状态日志和记分板日志。只有在调试期间，或者第一次为学生开启实验时，才可以这样做。

学生用浏览器访问如下网址请求炸弹：

**http\://$SERVER\_NAME:$REQUESTD\_PORT/**

学生用浏览器访问如下网址查看记分板：

**http\://$SERVER\_NAME:$REQUESTD\_PORT/scoreboard**

#### **4.4.2 较长版本**

（1）重置 Bomb Lab。“make stop” 确保没有服务器在运行。“make cleanallfiles” 重置实验，删除实验中特定实例的所有数据，例如状态日志、请求服务器创建的所有炸弹以及记分板日志。当你准备好将实验“上线”给学生时，就这样做。

你准备实验的时候，重置也很有用。在实验上线之前，你可能想为自己请求一些炸弹，运行它们，拆除一些，引爆一些，并确保结果在记分板上正确显示。如果出现问题（比如因为你忘记更新 src/config.h 中允许运行炸弹的机器列表），你可以修复配置，重置实验，然后请求并运行更多的测试炸弹。

**注意：如果你在开启实验后重新设置，你将丢失所有学生炸弹记录和他们的解答。你不能验证学生提交的内容。你的学生就得获得新的炸弹并重新开始。**

（2）开启 Bomb Lab。“make start” 运行 bomblab.pl，主守护进程启动并监视服务中的其他程序，每隔几秒检查它们的状态，如有必要则重启它们：

（3）停止 Bomb Lab。“make start” 会关闭所有正在运行的服务器。您可以随时开启和停止自动评分服务，而不会丢失任何信息。如果不确定服务状态，输入 “make stop; make start” 可以让一切都进入稳定状态。

请求服务器：请求服务器是一个简单的专用HTTP服务器，它（1）根据需要制作并向学生的浏览器提供自定义炸弹，（2）显示实时记分板的当前状态。

学生通过两个步骤从请求守护进程请求炸弹：

* 首先，学生用他们最喜欢的浏览器访问 **http\://$SERVER\_NAME:$REQUESTD\_PORT/。**&#x4F8B;如，<http://foo.cs.cmu.ed&#x75;**:**&#x31;5213/。请求服务器产生相应，将> HTML 表单发送回浏览器。
* 接着，学生用他们的用户名和电子邮件地址填写此表单，然后提交表单。请求服务器解析表单，制作一个 bombID = n 的定制的通知炸弹，并将 tar 文件发送到浏览器。然后学生将 tar 文件保存到磁盘上。当学生解压此文件时，会创建一个目录（./bomb），其中包含以下四个文件：

| 文件名          | 说明               |
| ------------ | ---------------- |
| bomb\*       | 定制的通知炸弹可执行程序     |
| bomb.c       | 主炸弹程序的源码         |
| ID           | 标识与该炸弹有关的学生      |
| README       | 列出炸弹号码、学生和电子邮件地址 |
| solution.txt | 该炸弹的解答           |

结果服务器：每次学生拆除一个阶段或引爆炸弹时，炸弹都会向结果服务器发送一条 HTTP 消息（称为自动结果字符串（autoresult string）），然后结果服务器将消息附加到记分板日志中。每个消息都包含一个 BombID、一个阶段和所发生事件的标示。如果是拆除事件，则消息还包含学生键入的“拆除字符串（defusing string）”以消除阶段。

报告守护进程：报告守护进程定期扫描记分板日志并更新网络记分板。对于每个炸弹，它统计爆炸的次数，最后一个拆除阶段，使用一个安静炸弹的副本验证每个最后拆除的阶段，并在一个标签分隔的文本文件中计算每个学生的分数，该文件名为 “scores. txt” 更新频率适中的配置变量 Bomblab.pm。

讲师和学生使用浏览器访问以下地址查看记分板：

**http\://$SERVER\_NAME:$REQUESTD\_PORT/scoreboard**

#### 4.4.3. 为**在线 Bomb Lab 评分**

在线的炸弹实验可以自己评分。在任何时间点，制表符分隔的文件（./bomblab/scores.txt)包含每个学生的最新分数。这个文件是由报告守护进程在每次生成新的记分板时创建的。

#### 4.4.4 在线 Bomb Lab 的补充说明

由于请求服务器和报告守护进程都需要执行炸弹，因此必须在 bomblab/src/config.h 文件的合法计算机列表中包含 $server\_NAME。

所有的服务器和守护进程都是无状态（stateless）的，所以您可以随意多次停止（“make stop”）和开启（“make start”）实验，而不会产生任何不良影响。如果您不小心杀死了其中一个守护进程，或者修改了一个守护进程，或者该守护进程由于某种原因死亡，那么请使用 “make stop” 进行清理，然后使用 “make start” 重新启动。如果 Linux 机器崩溃或重启，只需使用 “make start” 重新启动守护进程。

来自服务器的信息和错误消息被添加到“状态日志” bomblab/log-status.txt 中。服务器安静地运行，因此可以在启动时从 init.rc 脚本启动它们。

请参阅 src/README，了解更多关于炸弹的解剖结构以及它们是如何构造的。你不需要理解这些来提供实验，给出它们只是为了完整。

在将实验“上线”给学生之前，我们喜欢做些测试来检查一切，需键入以下内容：

```c
linux> make cleanallfiles   
linux> make start
```

然后我们用浏览器访问如下地址，为自己请求一个炸弹：

**http\://$SERVER\_NAME:$REQUESTD\_PORT**

在保存炸弹到磁盘后，我们将其解压，复制到 src/config.h 里已批准列表中的一台主机上，然后对其进行多次引爆和拆除，以确保爆炸和拆除正确记录在记分板上，可以在这里检查：

**http\://$SERVER\_NAME:$REQUESTD\_PORT/scoreboard**

一旦我们确信一切正常，我们就停止实验：

```c
linux> make stop
```

然后将其上线：

```c
linux> make cleanallfiles
linux> make start
```

一旦实验上线，我们可根据需要输入 “make stop” 和 “make start”，但要小心绝不能再次输入 “make cleanallfiles”。

#### 4.5 运行离线 Bomb Lab

在这个版本的实验中，你可以手动制作你自己的安静炸弹，然后把它们分发给学生。学生们在离线状态下（即，独立于任何自动评分服务）拆除炸弹，然后将他们的解答文件交给你，每个文件都由你手动评分。

你可以使用 makebomb.pl 脚本手动制作自己的炸弹。这个 makebomb.pl 脚本也生成炸弹的解答。键入 “./makebomb.pl -h” 查看其参数。

**选项 1：**&#x63D0;供离线炸弹实验室的最简单方法，是制造一个单一的通用炸弹，每个学生都试图将其拆除：

```c
linux> ./makebomb.pl -s ./src -b ./bombs
```

这会在 ./bombs/bomb0 下面创建一个通用炸弹和其他文件：

| 文件名          | 说明              |
| ------------ | --------------- |
| bomb\*       | 通用炸弹执行程序（分发给学生） |
| bomb.c       | 主程序的源代码（分发给学生）  |
| bomb-quiet\* | 请忽略该文件          |
| ID           | 请忽略该文件          |
| phases.c     | 炸弹阶段的 C 代码      |
| README       | 请忽略该文件          |
| solution.txt | 该炸弹的解答          |

你只向学生分发其中两个文件：./bomb 和./bomb.c。

学生提交他们的解答文件，你可以将解答输入给炸弹来验证：

```c
linux> cd bombs/bomb0
linux> ./bomb < student_solution.txt
```

这个选项对老师来说很容易，但是我们不推荐它，因为它太容易让学生作弊了。

**选项 2。**&#x63D0;供离线实验的另一个选项是使用 makebomb.pl 脚本，为每个学生制作一个唯一的定制的安静炸弹：

```c
linux> ./makebomb.pl -i <n> -s ./src -b ./bombs -l bomblab -u <email> -v <uid>
```

这将为电子邮件地址为 \<email> 且用户名为 \<uid> 的学生在 ./bombs/bomb 中创建一个定制的安静炸弹：

| 文件名          | 说明               |
| ------------ | ---------------- |
| bomb\*       | 定制的炸弹执行程序（分发给学生） |
| bomb.c       | 主程序的源代码（分发给学生）   |
| bomb-quiet\* | 请忽略该文件           |
| ID           | 标识与该炸弹关联的学生      |
| phases.c     | 炸弹阶段的 C 代码       |
| README       | 列出炸弹号码、学生和电子邮件地址 |
| solution.txt | 该炸弹的解答           |

你将向学生分发其中的四个文件：bomb、bomb.c、ID 和 README。

每个学生都将提交他们的解答文件，你可以针对运行他们的解答运行他们的定制炸弹，来手动验证：

```c
linux> cd ./bombs/bomb<n>
linux> ./bomb < student_n_solution.txt
```

不同阶段变种的源代码在 ./src/phases/ 中。
