]>
Commit | Line | Data |
---|---|---|
fbd26352 | 1 | /* Copyright (C) 2004-2019 Free Software Foundation, Inc. |
2f2c1efb | 2 | Contributed by Douglas B Rupp <rupp@gnat.com> |
3 | ||
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GCC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | Under Section 7 of GPL version 3, you are granted additional | |
17 | permissions described in the GCC Runtime Library Exception, version | |
18 | 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | You should have received a copy of the GNU General Public License and | |
21 | a copy of the GCC Runtime Library Exception along with this program; | |
22 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | <http://www.gnu.org/licenses/>. */ | |
24 | ||
25 | /* Locate the FDE entry for a given address, using VMS Starlet routines | |
26 | to avoid register/deregister calls at DSO load/unload. */ | |
27 | ||
28 | #include "tconfig.h" | |
29 | #include "tsystem.h" | |
30 | #include "coretypes.h" | |
31 | #include "tm.h" | |
022a2799 | 32 | #include "libgcc_tm.h" |
2f2c1efb | 33 | #include <stddef.h> |
34 | #include <stdlib.h> | |
35 | #include <stdio.h> | |
36 | #include "unwind-ia64.h" | |
37 | ||
6aadb6e2 | 38 | #include <ossddef.h> |
2f2c1efb | 39 | #ifndef SS$_NORMAL |
40 | #define SS$_NORMAL 1 | |
41 | #endif | |
42 | ||
611b540a | 43 | #define UNW_IVMS_MODE(HEADER) (((HEADER) >> 44) & 0x3L) |
44 | ||
2f2c1efb | 45 | typedef struct |
46 | { | |
6aadb6e2 | 47 | unw_word start_offset; |
48 | unw_word end_offset; | |
49 | unw_word info_offset; | |
50 | unw_word gp_value; | |
2f2c1efb | 51 | } vms_unw_table_entry; |
52 | ||
53 | typedef unsigned long long uqword; | |
54 | ||
55 | /* ENTRY is the unwind table entry found for a PC part of call chain we're | |
56 | unwinding through. Return whether we should force the generic unwinder | |
57 | to resort to "fallback" processing. */ | |
58 | ||
59 | static int | |
60 | force_fallback_processing_for (void * pc, vms_unw_table_entry * entry) | |
61 | { | |
62 | static int eh_debug = -1; | |
63 | ||
64 | uqword * unw_info_block = (uqword *)entry->info_offset; | |
65 | uqword header = *unw_info_block; | |
66 | ||
67 | /* We need to force fallback processing in two cases: | |
68 | ||
69 | 1/ The exception dispatch frame, since only our fallback | |
70 | processing knows how to properly unwind through it, and | |
71 | ||
72 | 2/ A bottom of stack frame, since only our fallback processing | |
73 | will ensure we don't try to unwind further past it, which | |
74 | would get us into unknown territory and likely cause a severe | |
75 | crash along the way. | |
76 | ||
77 | The two cases are indicated by non-default values for specific | |
78 | bits in the OS Specific Data (OSSD) General Information block | |
79 | associated with such frames. */ | |
80 | ||
81 | ossddef * ossd; | |
82 | ||
83 | if (eh_debug == -1) | |
84 | { | |
85 | char * EH_DEBUG = getenv ("EH_DEBUG"); | |
86 | eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0; | |
87 | } | |
88 | ||
89 | if (eh_debug) | |
90 | { | |
91 | printf ("pc @ 0x%p, block @ 0x%p, header = 0x%016llx\n", | |
92 | pc, unw_info_block, header); | |
93 | printf ("mode = %d, length = %ld, handler = %d\n", | |
94 | (int)UNW_IVMS_MODE (header), UNW_LENGTH (header), | |
95 | UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header)); | |
96 | } | |
97 | ||
98 | /* An OSSD block is there for IVMS_MODE == 3 only. */ | |
99 | if (UNW_IVMS_MODE (header) != 3) | |
100 | return 0; | |
101 | ||
102 | /* The OSSD block is found past the header, unwind descriptor area | |
103 | and condition handler pointer, if any. */ | |
104 | ossd = (ossddef *) | |
105 | /* Beware: uqword pointer arithmetic below. */ | |
106 | (unw_info_block | |
107 | + 1 | |
108 | + UNW_LENGTH (header) | |
109 | + (UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header))); | |
110 | ||
111 | /* "A General Information segment may be omitted if all of its fields | |
112 | would have their default values. If a General Information segment | |
113 | is present, it must be the first in the OSSD area." So ... */ | |
114 | ||
115 | if (eh_debug) | |
116 | printf ("ossd @ 0x%p\n", ossd); | |
117 | ||
118 | if (eh_debug && ossd->ossd$v_type == OSSD$K_GENERAL_INFO) | |
119 | printf ("exc_frame = %d - bot_frame = %d - base_frame = %d\n", | |
120 | ossd->ossd$v_exception_frame, | |
121 | ossd->ossd$v_bottom_of_stack, | |
122 | ossd->ossd$v_base_frame); | |
123 | ||
124 | return | |
125 | ossd->ossd$v_type == OSSD$K_GENERAL_INFO | |
126 | && (ossd->ossd$v_exception_frame | |
127 | || ossd->ossd$v_bottom_of_stack || ossd->ossd$v_base_frame); | |
128 | } | |
129 | ||
130 | /* Return a pointer to the unwind table entry for the function | |
131 | containing PC, 0 if we cannot find an entry or if the one we find | |
132 | calls for fallback processing. */ | |
133 | ||
134 | struct unw_table_entry * | |
6aadb6e2 | 135 | _Unwind_FindTableEntry (void *pc, unw_word *segment_base, |
136 | unw_word *gp, struct unw_table_entry *ent) | |
2f2c1efb | 137 | { |
138 | vms_unw_table_entry vueblock; | |
139 | ||
140 | if (SYS$GET_UNWIND_ENTRY_INFO (pc, &vueblock, 0) != SS$_NORMAL) | |
141 | return 0; | |
142 | ||
143 | /* If there is no unwind information, use fallback. */ | |
144 | if (vueblock.info_offset == 0) | |
145 | return 0; | |
146 | ||
147 | /* If we need to force fallback processing, just pretend there is | |
148 | no entry. */ | |
149 | if (force_fallback_processing_for (pc, &vueblock)) | |
150 | return 0; | |
151 | ||
152 | *segment_base = 0; /* ??? Fixme. ??? */ | |
153 | *gp = vueblock.gp_value; | |
154 | ent->start_offset = vueblock.start_offset; | |
155 | ent->end_offset = vueblock.end_offset; | |
156 | ent->info_offset = vueblock.info_offset; | |
157 | ||
158 | return ent; | |
159 | } |