#include "mini-unwind.h"
#include <mono/utils/mono-counters.h>
+#include <mono/utils/freebsd-dwarf.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/mono-endian.h>
dwarf_reg_to_hw_reg_inited = TRUE;
}
-static inline int
+int
mono_dwarf_reg_to_hw_reg (int reg)
{
if (!dwarf_reg_to_hw_reg_inited)
* Decode the Language Specific Data Area generated by LLVM.
*/
static void
-decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info)
+decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
{
gint32 ttype_offset, call_site_length;
gint32 ttype_encoding, call_site_encoding;
*/
p = lsda;
- /* Read @LPStart */
- g_assert (*p == DW_EH_PE_omit);
- p ++;
+ if (*p == DW_EH_PE_udata4) {
+ /* This is the modified LSDA generated by the LLVM mono branch */
+ guint32 mono_magic, version;
+ gint32 op, reg, offset;
+
+ p ++;
+ mono_magic = decode_uleb128 (p, &p);
+ g_assert (mono_magic == 0x4d4fef4f);
+ version = decode_uleb128 (p, &p);
+ g_assert (version == 1);
+
+ /* 'this' location */
+ op = *p;
+ g_assert (op == DW_OP_bregx);
+ p ++;
+ reg = decode_uleb128 (p, &p);
+ offset = decode_sleb128 (p, &p);
+
+ *this_reg = mono_dwarf_reg_to_hw_reg (reg);
+ *this_offset = offset;
+ } else {
+ /* Read @LPStart */
+ g_assert (*p == DW_EH_PE_omit);
+ p ++;
+
+ *this_reg = -1;
+ *this_offset = -1;
+ }
/* Read @TType */
ttype_encoding = *p;
while (p < action_table) {
int block_start_offset, block_size, landing_pad, action_offset;
- block_start_offset = ((guint32*)p) [0];
- block_size = ((guint32*)p) [1];
- landing_pad = ((guint32*)p) [2];
- p += 3 * sizeof (guint32);
+ block_start_offset = read32 (p);
+ p += sizeof (gint32);
+ block_size = read32 (p);
+ p += sizeof (gint32);
+ landing_pad = read32 (p);
+ p += sizeof (gint32);
action_offset = decode_uleb128 (p, &p);
/* landing_pad == 0 means the region has no landing pad */
int block_start_offset, block_size, landing_pad, action_offset, type_offset;
guint8 *action, *tinfo;
- block_start_offset = ((guint32*)p) [0];
- block_size = ((guint32*)p) [1];
- landing_pad = ((guint32*)p) [2];
- p += 3 * sizeof (guint32);
+ block_start_offset = read32 (p);
+ p += sizeof (gint32);
+ block_size = read32 (p);
+ p += sizeof (gint32);
+ landing_pad = read32 (p);
+ p += sizeof (gint32);
action_offset = decode_uleb128 (p, &p);
action = action_table + action_offset - 1;
if (landing_pad) {
//printf ("BLOCK: %p-%p %p, %d\n", code + block_start_offset, code + block_start_offset + block_size, code + landing_pad, action_offset);
+ g_assert (ttype_offset);
+
if (ttype_encoding == DW_EH_PE_absptr) {
guint8 *ttype_entry = (ttype - (type_offset * sizeof (gpointer)));
tinfo = *(gpointer*)ttype_entry;
* LSDA.
*/
guint8*
-mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info)
+mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
{
- guint8 *p, *cie, *fde_current, *fde_aug, *code, *fde_cfi, *cie_cfi;
+ guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
gint32 i, cie_aug_len, buf_len;
char *cie_aug_str;
guint8 *buf;
+ gboolean has_fde_augmentation = FALSE;
/*
* http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
*/
+ *type_info = NULL;
+ *this_reg = -1;
+ *this_offset = -1;
+
/* Decode FDE */
p = fde;
data_align = decode_sleb128 (p, &p);
return_reg = decode_uleb128 (p, &p);
if (strstr (cie_aug_str, "z")) {
- cie_aug_len = decode_uleb128 (p, &p);
-
- g_assert (!strcmp (cie_aug_str, "zR") || !strcmp (cie_aug_str, "zPLR"));
+ guint8 *cie_aug;
+ guint32 p_encoding;
- /* Check that the augmention is what we expect */
- if (!strcmp (cie_aug_str, "zPLR")) {
- guint8 *cie_aug = p;
- guint32 p_encoding;
-
- /* P */
- p_encoding = *p;
- p ++;
- read_encoded_val (p_encoding, p, &p);
+ cie_aug_len = decode_uleb128 (p, &p);
- /* L */
- g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
- p ++;
- /* R */
- g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
- p ++;
+ has_fde_augmentation = TRUE;
- g_assert (p - cie_aug == cie_aug_len);
-
- p = cie_aug;
+ cie_aug = p;
+ for (i = 0; cie_aug_str [i] != '\0'; ++i) {
+ switch (cie_aug_str [i]) {
+ case 'z':
+ break;
+ case 'P':
+ p_encoding = *p;
+ p ++;
+ read_encoded_val (p_encoding, p, &p);
+ break;
+ case 'L':
+ g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
+ p ++;
+ break;
+ case 'R':
+ g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
+ p ++;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
}
+
+ p = cie_aug;
p += cie_aug_len;
}
cie_cfi = p;
p += 4;
pc_range = *(guint32*)p;
p += 4;
- aug_len = decode_uleb128 (p, &p);
- fde_aug = p;
- p += aug_len;
+ if (has_fde_augmentation) {
+ aug_len = decode_uleb128 (p, &p);
+ fde_aug = p;
+ p += aug_len;
+ } else {
+ aug_len = 0;
+ }
fde_cfi = p;
fde_data_len = fde + 4 + fde_len - p;
/* sdata|pcrel encoding */
if (aug_len == 4)
- lsda_offset = *(gint64*)fde_aug;
+ lsda_offset = read32 (fde_aug);
else if (aug_len == 8)
- lsda_offset = *(gint32*)fde_aug;
+ lsda_offset = *(gint64*)fde_aug;
else
g_assert_not_reached ();
if (lsda_offset != 0) {
- lsda = fde_aug + *(gint32*)fde_aug;
+ lsda = fde_aug + lsda_offset;
- decode_lsda (lsda, code, ex_info, ex_info_len, type_info);
+ decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
}
}
GSList*
mono_unwind_get_cie_program (void)
{
-#ifdef TARGET_AMD64
+#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
return mono_arch_get_cie_program ();
-#elif defined(TARGET_POWERPC)
- GSList *l = NULL;
-
- mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
-
- return l;
#else
return NULL;
#endif