]>
Commit | Line | Data |
---|---|---|
201cdb74 | 1 | /* Copyright (C) 2004, 2009, 2011 Free Software Foundation, Inc. |
b874a90d DR |
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" | |
32 | #include <stddef.h> | |
33 | #include <stdlib.h> | |
34 | #include <stdio.h> | |
201cdb74 | 35 | #include "md-unwind-support.h" |
b874a90d DR |
36 | #include "unwind-ia64.h" |
37 | ||
38 | #define __int64 long | |
39 | #include <vms/ossddef.h> | |
40 | #ifndef SS$_NORMAL | |
41 | #define SS$_NORMAL 1 | |
42 | #endif | |
43 | ||
44 | typedef struct | |
45 | { | |
46 | unsigned long start_offset; | |
47 | unsigned long end_offset; | |
48 | unsigned long info_offset; | |
49 | unsigned long gp_value; | |
50 | } vms_unw_table_entry; | |
51 | ||
52 | typedef unsigned long long uqword; | |
53 | ||
54 | /* ENTRY is the unwind table entry found for a PC part of call chain we're | |
55 | unwinding through. Return whether we should force the generic unwinder | |
56 | to resort to "fallback" processing. */ | |
57 | ||
58 | static int | |
59 | force_fallback_processing_for (void * pc, vms_unw_table_entry * entry) | |
60 | { | |
61 | static int eh_debug = -1; | |
62 | ||
63 | uqword * unw_info_block = (uqword *)entry->info_offset; | |
64 | uqword header = *unw_info_block; | |
65 | ||
66 | /* We need to force fallback processing in two cases: | |
67 | ||
68 | 1/ The exception dispatch frame, since only our fallback | |
69 | processing knows how to properly unwind through it, and | |
70 | ||
71 | 2/ A bottom of stack frame, since only our fallback processing | |
72 | will ensure we don't try to unwind further past it, which | |
73 | would get us into unknown territory and likely cause a severe | |
74 | crash along the way. | |
75 | ||
76 | The two cases are indicated by non-default values for specific | |
77 | bits in the OS Specific Data (OSSD) General Information block | |
78 | associated with such frames. */ | |
79 | ||
80 | ossddef * ossd; | |
81 | ||
82 | if (eh_debug == -1) | |
83 | { | |
84 | char * EH_DEBUG = getenv ("EH_DEBUG"); | |
85 | eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0; | |
86 | } | |
87 | ||
88 | if (eh_debug) | |
89 | { | |
90 | printf ("pc @ 0x%p, block @ 0x%p, header = 0x%016llx\n", | |
91 | pc, unw_info_block, header); | |
92 | printf ("mode = %d, length = %ld, handler = %d\n", | |
93 | (int)UNW_IVMS_MODE (header), UNW_LENGTH (header), | |
94 | UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header)); | |
95 | } | |
96 | ||
97 | /* An OSSD block is there for IVMS_MODE == 3 only. */ | |
98 | if (UNW_IVMS_MODE (header) != 3) | |
99 | return 0; | |
100 | ||
101 | /* The OSSD block is found past the header, unwind descriptor area | |
102 | and condition handler pointer, if any. */ | |
103 | ossd = (ossddef *) | |
104 | /* Beware: uqword pointer arithmetic below. */ | |
105 | (unw_info_block | |
106 | + 1 | |
107 | + UNW_LENGTH (header) | |
108 | + (UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header))); | |
109 | ||
110 | /* "A General Information segment may be omitted if all of its fields | |
111 | would have their default values. If a General Information segment | |
112 | is present, it must be the first in the OSSD area." So ... */ | |
113 | ||
114 | if (eh_debug) | |
115 | printf ("ossd @ 0x%p\n", ossd); | |
116 | ||
117 | if (eh_debug && ossd->ossd$v_type == OSSD$K_GENERAL_INFO) | |
118 | printf ("exc_frame = %d - bot_frame = %d - base_frame = %d\n", | |
119 | ossd->ossd$v_exception_frame, | |
120 | ossd->ossd$v_bottom_of_stack, | |
121 | ossd->ossd$v_base_frame); | |
122 | ||
123 | return | |
124 | ossd->ossd$v_type == OSSD$K_GENERAL_INFO | |
125 | && (ossd->ossd$v_exception_frame | |
126 | || ossd->ossd$v_bottom_of_stack || ossd->ossd$v_base_frame); | |
127 | } | |
128 | ||
129 | /* Return a pointer to the unwind table entry for the function | |
130 | containing PC, 0 if we cannot find an entry or if the one we find | |
131 | calls for fallback processing. */ | |
132 | ||
133 | struct unw_table_entry * | |
134 | _Unwind_FindTableEntry (void *pc, unsigned long *segment_base, | |
135 | unsigned long *gp, struct unw_table_entry *ent) | |
136 | { | |
137 | vms_unw_table_entry vueblock; | |
138 | ||
139 | if (SYS$GET_UNWIND_ENTRY_INFO (pc, &vueblock, 0) != SS$_NORMAL) | |
140 | return 0; | |
141 | ||
142 | /* If there is no unwind information, use fallback. */ | |
143 | if (vueblock.info_offset == 0) | |
144 | return 0; | |
145 | ||
146 | /* If we need to force fallback processing, just pretend there is | |
147 | no entry. */ | |
148 | if (force_fallback_processing_for (pc, &vueblock)) | |
149 | return 0; | |
150 | ||
151 | *segment_base = 0; /* ??? Fixme. ??? */ | |
152 | *gp = vueblock.gp_value; | |
153 | ent->start_offset = vueblock.start_offset; | |
154 | ent->end_offset = vueblock.end_offset; | |
155 | ent->info_offset = vueblock.info_offset; | |
156 | ||
157 | return ent; | |
158 | } |