[译]C++异常的幕后17:异常类型的发射以及读.gcc_except_table

栏目: C++ · 发布时间: 4年前

内容简介:目前为止我们知道在抛出一个异常时,通过阅读本地储存区,即.gcc_except_table,我们可以得到许多反射信息;读这个表我们已经能够实现能决定在抛出一个异常时运行哪个着陆垫的personality函数。我们还知道如何读LSDA的活动表部分,因此我们应该能够修改personality函数在带有多个catch的着陆垫内选择正确的catch语句。上次我们留下了我们的ABI实现,并把一些时间用于分析.gcc_except_table的汇编来发掘我们如何找出catch可以处理的类型。我们发现这张表的部分确实保存

作者: nicolasbrailo

目前为止我们知道在抛出一个异常时,通过阅读本地储存区,即.gcc_except_table,我们可以得到许多反射信息;读这个表我们已经能够实现能决定在抛出一个异常时运行哪个着陆垫的personality函数。我们还知道如何读LSDA的活动表部分,因此我们应该能够修改personality函数在带有多个catch的着陆垫内选择正确的catch语句。

上次我们留下了我们的ABI实现,并把一些时间用于分析.gcc_except_table的汇编来发掘我们如何找出catch可以处理的类型。我们发现这张表的部分确实保存了一个类型列表,可以找到这个消息。让我们尝试在清理阶段读它,但首先让我们回忆LSDA头的定义:

1

2

3

4

5

6

7

struct LSDA_Header {

    uint8_t start_encoding;

    uint8_t type_encoding;

 

    // This is the offset, from the end of the header, to the types table

    uint8_t type_table_offset;

};

最后一个域是新的(对我们):它向我们给出了类型表的一个偏移。让我们回忆一下每个调用点的定义:

1

2

3

4

5

6

7

8

9

10

struct LSDA_CS {

    // Offset into function from which we could handle a throw

    uint8_t start;

    // Length of the block that might throw

    uint8_t len;

    // Landing pad

    uint8_t lp;

    // Offset into action table + 1 (0 means no action)

    uint8_t action;

};

检查最后这个域“action”。这向我们给出活动表的一个偏移。这意味着我们可以对一个特定CS找到该活动。这里的技巧是对存在一个catch的着陆垫,这个活动将保存该类型表的偏移;我们可以使用类型表指针的偏移,这我们可以从头部获得。相当拗口:让我们更好地讨论代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

// Pointer to the beginning of the raw LSDA

LSDA_ptr lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);

 

// Read LSDA headerfor the LSDA

LSDA_Header header(&lsda);

 

const LSDA_ptr types_table_start = lsda + header.type_table_offset;

 

// Read the LSDA CS header

LSDA_CS_Header cs_header(&lsda);

 

// Calculate where the end of the LSDA CS table is

const LSDA_ptr lsda_cs_table_end = lsda + cs_header.length;

 

// Get the start of action tables

const LSDA_ptr action_tbl_start = lsda_cs_table_end;

 

// Get the first call site

LSDA_CS cs(&lsda);

 

// cs.action is the offset + 1; that way cs.action == 0

// means there is no associated entry in the action table

const size_t action_offset = cs.action - 1;

const LSDA_ptr action = action_tbl_start + action_offset;

 

// For a landing pad with a catch the action table will

// hold an index to a list of types

int type_index = action[0];

 

// types_table_start actually points to the end of the table, so

// we need to invert the type_index. There we'll find a ptr to

// the std::type_info for the specification in our catch

const void* catch_type_info = types_table_start[ -1 * type_index ];

const std::type_info *catch_ti = (const std::type_info *) catch_type_info;

 

// If everything went OK, this should print something like Fake_Exception

printf("%s\n", catch_ti->name());

代码看起来复杂,因为在到达结构体type_info之前有几层间接层,不过这并不复杂:它只是读我们在汇编里找到的.gcc_except_table。

打印类型名是正确方向上前进的一大步。同样,我们的personality函数变得有点混乱。读LSDA的大部分复杂性可以隐藏在底下,几乎没有代价。你可以在这里检查 我的实现

下次我们将看看是否能把新发现的类型匹配到原有的异常。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入浅出HTML5编程

深入浅出HTML5编程

弗里曼 (Eric Friiman)、罗布森 (Elisabdth Robson) / 东南大学出版社 / 2012-4 / 98.00元

《深入浅出HTML5编程(影印版)(英文)》就是你的特快车票,它可以带你学习如何使用今天的标准同时也会是明日的最佳实践来搭建Web应用。同时,你会了解HTML5的新API的基本知识,甚至你还会弄明白这些API是如何与你的网页进行交互,JaVaScript如何为它们提供动力,以及你如何使用它们来搭建能够打动你的老板并且吸引你的朋友的Web应用。一起来看看 《深入浅出HTML5编程》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具