Commit | Line | Data |
---|---|---|
7ed49443 JB |
1 | /* Abstraction of GNU v3 abi. |
2 | Contributed by Jim Blandy <jimb@redhat.com> | |
451fbdda | 3 | |
197e01b6 | 4 | Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. |
7ed49443 JB |
5 | |
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or | |
9 | modify it under the terms of the GNU General Public License as | |
10 | published by the Free Software Foundation; either version 2 of the | |
11 | License, or (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
197e01b6 EZ |
20 | Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | Boston, MA 02110-1301, USA. */ | |
7ed49443 JB |
22 | |
23 | #include "defs.h" | |
24 | #include "value.h" | |
25 | #include "cp-abi.h" | |
362ff856 | 26 | #include "cp-support.h" |
7ed49443 | 27 | #include "demangle.h" |
3d499020 | 28 | #include "gdb_assert.h" |
5f8a3188 | 29 | #include "gdb_string.h" |
7ed49443 | 30 | |
b27b8843 | 31 | static struct cp_abi_ops gnu_v3_abi_ops; |
7ed49443 JB |
32 | |
33 | static int | |
34 | gnuv3_is_vtable_name (const char *name) | |
35 | { | |
36 | return strncmp (name, "_ZTV", 4) == 0; | |
37 | } | |
38 | ||
39 | static int | |
40 | gnuv3_is_operator_name (const char *name) | |
41 | { | |
42 | return strncmp (name, "operator", 8) == 0; | |
43 | } | |
44 | ||
45 | ||
46 | /* To help us find the components of a vtable, we build ourselves a | |
47 | GDB type object representing the vtable structure. Following the | |
48 | V3 ABI, it goes something like this: | |
49 | ||
50 | struct gdb_gnu_v3_abi_vtable { | |
51 | ||
52 | / * An array of virtual call and virtual base offsets. The real | |
53 | length of this array depends on the class hierarchy; we use | |
54 | negative subscripts to access the elements. Yucky, but | |
55 | better than the alternatives. * / | |
56 | ptrdiff_t vcall_and_vbase_offsets[0]; | |
57 | ||
58 | / * The offset from a virtual pointer referring to this table | |
59 | to the top of the complete object. * / | |
60 | ptrdiff_t offset_to_top; | |
61 | ||
62 | / * The type_info pointer for this class. This is really a | |
63 | std::type_info *, but GDB doesn't really look at the | |
64 | type_info object itself, so we don't bother to get the type | |
65 | exactly right. * / | |
66 | void *type_info; | |
67 | ||
68 | / * Virtual table pointers in objects point here. * / | |
69 | ||
70 | / * Virtual function pointers. Like the vcall/vbase array, the | |
71 | real length of this table depends on the class hierarchy. * / | |
72 | void (*virtual_functions[0]) (); | |
73 | ||
74 | }; | |
75 | ||
76 | The catch, of course, is that the exact layout of this table | |
77 | depends on the ABI --- word size, endianness, alignment, etc. So | |
78 | the GDB type object is actually a per-architecture kind of thing. | |
79 | ||
80 | vtable_type_gdbarch_data is a gdbarch per-architecture data pointer | |
81 | which refers to the struct type * for this structure, laid out | |
82 | appropriately for the architecture. */ | |
b27b8843 | 83 | static struct gdbarch_data *vtable_type_gdbarch_data; |
7ed49443 JB |
84 | |
85 | ||
86 | /* Human-readable names for the numbers of the fields above. */ | |
87 | enum { | |
88 | vtable_field_vcall_and_vbase_offsets, | |
89 | vtable_field_offset_to_top, | |
90 | vtable_field_type_info, | |
91 | vtable_field_virtual_functions | |
92 | }; | |
93 | ||
94 | ||
95 | /* Return a GDB type representing `struct gdb_gnu_v3_abi_vtable', | |
96 | described above, laid out appropriately for ARCH. | |
97 | ||
98 | We use this function as the gdbarch per-architecture data | |
99 | initialization function. We assume that the gdbarch framework | |
100 | calls the per-architecture data initialization functions after it | |
101 | sets current_gdbarch to the new architecture. */ | |
102 | static void * | |
103 | build_gdb_vtable_type (struct gdbarch *arch) | |
104 | { | |
105 | struct type *t; | |
106 | struct field *field_list, *field; | |
107 | int offset; | |
108 | ||
109 | struct type *void_ptr_type | |
110 | = lookup_pointer_type (builtin_type_void); | |
111 | struct type *ptr_to_void_fn_type | |
112 | = lookup_pointer_type (lookup_function_type (builtin_type_void)); | |
113 | ||
114 | /* ARCH can't give us the true ptrdiff_t type, so we guess. */ | |
115 | struct type *ptrdiff_type | |
116 | = init_type (TYPE_CODE_INT, TARGET_PTR_BIT / TARGET_CHAR_BIT, 0, | |
117 | "ptrdiff_t", 0); | |
118 | ||
119 | /* We assume no padding is necessary, since GDB doesn't know | |
120 | anything about alignment at the moment. If this assumption bites | |
121 | us, we should add a gdbarch method which, given a type, returns | |
122 | the alignment that type requires, and then use that here. */ | |
123 | ||
124 | /* Build the field list. */ | |
125 | field_list = xmalloc (sizeof (struct field [4])); | |
126 | memset (field_list, 0, sizeof (struct field [4])); | |
127 | field = &field_list[0]; | |
128 | offset = 0; | |
129 | ||
130 | /* ptrdiff_t vcall_and_vbase_offsets[0]; */ | |
131 | FIELD_NAME (*field) = "vcall_and_vbase_offsets"; | |
132 | FIELD_TYPE (*field) | |
133 | = create_array_type (0, ptrdiff_type, | |
134 | create_range_type (0, builtin_type_int, 0, -1)); | |
135 | FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT; | |
136 | offset += TYPE_LENGTH (FIELD_TYPE (*field)); | |
137 | field++; | |
138 | ||
139 | /* ptrdiff_t offset_to_top; */ | |
140 | FIELD_NAME (*field) = "offset_to_top"; | |
141 | FIELD_TYPE (*field) = ptrdiff_type; | |
142 | FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT; | |
143 | offset += TYPE_LENGTH (FIELD_TYPE (*field)); | |
144 | field++; | |
145 | ||
146 | /* void *type_info; */ | |
147 | FIELD_NAME (*field) = "type_info"; | |
148 | FIELD_TYPE (*field) = void_ptr_type; | |
149 | FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT; | |
150 | offset += TYPE_LENGTH (FIELD_TYPE (*field)); | |
151 | field++; | |
152 | ||
153 | /* void (*virtual_functions[0]) (); */ | |
154 | FIELD_NAME (*field) = "virtual_functions"; | |
155 | FIELD_TYPE (*field) | |
156 | = create_array_type (0, ptr_to_void_fn_type, | |
157 | create_range_type (0, builtin_type_int, 0, -1)); | |
158 | FIELD_BITPOS (*field) = offset * TARGET_CHAR_BIT; | |
159 | offset += TYPE_LENGTH (FIELD_TYPE (*field)); | |
160 | field++; | |
161 | ||
162 | /* We assumed in the allocation above that there were four fields. */ | |
3d499020 | 163 | gdb_assert (field == (field_list + 4)); |
7ed49443 JB |
164 | |
165 | t = init_type (TYPE_CODE_STRUCT, offset, 0, 0, 0); | |
166 | TYPE_NFIELDS (t) = field - field_list; | |
167 | TYPE_FIELDS (t) = field_list; | |
168 | TYPE_TAG_NAME (t) = "gdb_gnu_v3_abi_vtable"; | |
169 | ||
170 | return t; | |
171 | } | |
172 | ||
173 | ||
174 | /* Return the offset from the start of the imaginary `struct | |
175 | gdb_gnu_v3_abi_vtable' object to the vtable's "address point" | |
176 | (i.e., where objects' virtual table pointers point). */ | |
177 | static int | |
5ae5f592 | 178 | vtable_address_point_offset (void) |
7ed49443 | 179 | { |
451fbdda AC |
180 | struct type *vtable_type = gdbarch_data (current_gdbarch, |
181 | vtable_type_gdbarch_data); | |
7ed49443 JB |
182 | |
183 | return (TYPE_FIELD_BITPOS (vtable_type, vtable_field_virtual_functions) | |
184 | / TARGET_CHAR_BIT); | |
185 | } | |
186 | ||
187 | ||
188 | static struct type * | |
189 | gnuv3_rtti_type (struct value *value, | |
190 | int *full_p, int *top_p, int *using_enc_p) | |
191 | { | |
451fbdda AC |
192 | struct type *vtable_type = gdbarch_data (current_gdbarch, |
193 | vtable_type_gdbarch_data); | |
df407dfe | 194 | struct type *values_type = check_typedef (value_type (value)); |
7ed49443 JB |
195 | CORE_ADDR vtable_address; |
196 | struct value *vtable; | |
197 | struct minimal_symbol *vtable_symbol; | |
198 | const char *vtable_symbol_name; | |
199 | const char *class_name; | |
7ed49443 | 200 | struct type *run_time_type; |
21cfb3b6 | 201 | struct type *base_type; |
7ed49443 JB |
202 | LONGEST offset_to_top; |
203 | ||
204 | /* We only have RTTI for class objects. */ | |
df407dfe | 205 | if (TYPE_CODE (values_type) != TYPE_CODE_CLASS) |
7ed49443 JB |
206 | return NULL; |
207 | ||
df407dfe | 208 | /* If we can't find the virtual table pointer for values_type, we |
7ed49443 | 209 | can't find the RTTI. */ |
df407dfe AC |
210 | fill_in_vptr_fieldno (values_type); |
211 | if (TYPE_VPTR_FIELDNO (values_type) == -1) | |
7ed49443 JB |
212 | return NULL; |
213 | ||
21cfb3b6 DJ |
214 | if (using_enc_p) |
215 | *using_enc_p = 0; | |
216 | ||
7ed49443 | 217 | /* Fetch VALUE's virtual table pointer, and tweak it to point at |
21cfb3b6 | 218 | an instance of our imaginary gdb_gnu_v3_abi_vtable structure. */ |
df407dfe AC |
219 | base_type = check_typedef (TYPE_VPTR_BASETYPE (values_type)); |
220 | if (values_type != base_type) | |
21cfb3b6 DJ |
221 | { |
222 | value = value_cast (base_type, value); | |
223 | if (using_enc_p) | |
224 | *using_enc_p = 1; | |
225 | } | |
7ed49443 | 226 | vtable_address |
df407dfe | 227 | = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (values_type))); |
7ed49443 | 228 | vtable = value_at_lazy (vtable_type, |
00a4c844 | 229 | vtable_address - vtable_address_point_offset ()); |
7ed49443 JB |
230 | |
231 | /* Find the linker symbol for this vtable. */ | |
232 | vtable_symbol | |
233 | = lookup_minimal_symbol_by_pc (VALUE_ADDRESS (vtable) | |
df407dfe | 234 | + value_offset (vtable) |
13c3b5f5 | 235 | + value_embedded_offset (vtable)); |
7ed49443 JB |
236 | if (! vtable_symbol) |
237 | return NULL; | |
238 | ||
239 | /* The symbol's demangled name should be something like "vtable for | |
240 | CLASS", where CLASS is the name of the run-time type of VALUE. | |
241 | If we didn't like this approach, we could instead look in the | |
242 | type_info object itself to get the class name. But this way | |
243 | should work just as well, and doesn't read target memory. */ | |
244 | vtable_symbol_name = SYMBOL_DEMANGLED_NAME (vtable_symbol); | |
98081e55 PB |
245 | if (vtable_symbol_name == NULL |
246 | || strncmp (vtable_symbol_name, "vtable for ", 11)) | |
f773fdbb | 247 | { |
8a3fe4f8 | 248 | warning (_("can't find linker symbol for virtual table for `%s' value"), |
df407dfe | 249 | TYPE_NAME (values_type)); |
f773fdbb | 250 | if (vtable_symbol_name) |
8a3fe4f8 | 251 | warning (_(" found `%s' instead"), vtable_symbol_name); |
f773fdbb JM |
252 | return NULL; |
253 | } | |
7ed49443 JB |
254 | class_name = vtable_symbol_name + 11; |
255 | ||
256 | /* Try to look up the class name as a type name. */ | |
362ff856 MC |
257 | /* FIXME: chastain/2003-11-26: block=NULL is bogus. See pr gdb/1465. */ |
258 | run_time_type = cp_lookup_rtti_type (class_name, NULL); | |
259 | if (run_time_type == NULL) | |
260 | return NULL; | |
7ed49443 JB |
261 | |
262 | /* Get the offset from VALUE to the top of the complete object. | |
263 | NOTE: this is the reverse of the meaning of *TOP_P. */ | |
264 | offset_to_top | |
265 | = value_as_long (value_field (vtable, vtable_field_offset_to_top)); | |
266 | ||
267 | if (full_p) | |
13c3b5f5 | 268 | *full_p = (- offset_to_top == value_embedded_offset (value) |
4754a64e | 269 | && (TYPE_LENGTH (value_enclosing_type (value)) |
7ed49443 JB |
270 | >= TYPE_LENGTH (run_time_type))); |
271 | if (top_p) | |
272 | *top_p = - offset_to_top; | |
7ed49443 JB |
273 | |
274 | return run_time_type; | |
275 | } | |
276 | ||
277 | ||
278 | static struct value * | |
279 | gnuv3_virtual_fn_field (struct value **value_p, | |
280 | struct fn_field *f, int j, | |
281 | struct type *type, int offset) | |
282 | { | |
451fbdda AC |
283 | struct type *vtable_type = gdbarch_data (current_gdbarch, |
284 | vtable_type_gdbarch_data); | |
7ed49443 | 285 | struct value *value = *value_p; |
df407dfe | 286 | struct type *values_type = check_typedef (value_type (value)); |
7ed49443 JB |
287 | struct type *vfn_base; |
288 | CORE_ADDR vtable_address; | |
289 | struct value *vtable; | |
290 | struct value *vfn; | |
291 | ||
292 | /* Some simple sanity checks. */ | |
df407dfe | 293 | if (TYPE_CODE (values_type) != TYPE_CODE_CLASS) |
8a3fe4f8 | 294 | error (_("Only classes can have virtual functions.")); |
7ed49443 JB |
295 | |
296 | /* Find the base class that defines this virtual function. */ | |
297 | vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j); | |
298 | if (! vfn_base) | |
299 | /* In programs compiled with G++ version 1, the debug info doesn't | |
300 | say which base class defined the virtual function. We'll guess | |
301 | it's the same base class that has our vtable; this is wrong for | |
302 | multiple inheritance, but it's better than nothing. */ | |
303 | vfn_base = TYPE_VPTR_BASETYPE (type); | |
304 | ||
305 | /* This type may have been defined before its virtual function table | |
306 | was. If so, fill in the virtual function table entry for the | |
307 | type now. */ | |
308 | if (TYPE_VPTR_FIELDNO (vfn_base) < 0) | |
309 | fill_in_vptr_fieldno (vfn_base); | |
cef4f5dd | 310 | if (TYPE_VPTR_FIELDNO (vfn_base) < 0) |
8a3fe4f8 | 311 | error (_("Could not find virtual table pointer for class \"%s\"."), |
cef4f5dd | 312 | TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>"); |
7ed49443 JB |
313 | |
314 | /* Now that we know which base class is defining our virtual | |
315 | function, cast our value to that baseclass. This takes care of | |
316 | any necessary `this' adjustments. */ | |
df407dfe | 317 | if (vfn_base != values_type) |
21cfb3b6 | 318 | value = value_cast (vfn_base, value); |
7ed49443 JB |
319 | |
320 | /* Now value is an object of the appropriate base type. Fetch its | |
321 | virtual table. */ | |
21cfb3b6 | 322 | /* It might be possible to do this cast at the same time as the above. |
76b79d6e DJ |
323 | Does multiple inheritance affect this? |
324 | Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent? | |
325 | */ | |
21cfb3b6 DJ |
326 | if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base) |
327 | value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value); | |
7ed49443 | 328 | vtable_address |
1aa20aa8 | 329 | = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base))); |
21cfb3b6 | 330 | |
7ed49443 | 331 | vtable = value_at_lazy (vtable_type, |
00a4c844 | 332 | vtable_address - vtable_address_point_offset ()); |
7ed49443 JB |
333 | |
334 | /* Fetch the appropriate function pointer from the vtable. */ | |
335 | vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions), | |
336 | value_from_longest (builtin_type_int, | |
337 | TYPE_FN_FIELD_VOFFSET (f, j))); | |
338 | ||
339 | /* Cast the function pointer to the appropriate type. */ | |
340 | vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)), | |
341 | vfn); | |
342 | ||
76b79d6e DJ |
343 | /* Is (type)value always numerically the same as (vfn_base)value? |
344 | If so we can spare this cast and use one of the ones above. */ | |
345 | *value_p = value_addr (value_cast (type, *value_p)); | |
346 | ||
7ed49443 JB |
347 | return vfn; |
348 | } | |
349 | ||
1514d34e DJ |
350 | /* Compute the offset of the baseclass which is |
351 | the INDEXth baseclass of class TYPE, | |
352 | for value at VALADDR (in host) at ADDRESS (in target). | |
353 | The result is the offset of the baseclass value relative | |
354 | to (the address of)(ARG) + OFFSET. | |
355 | ||
356 | -1 is returned on error. */ | |
b9362cc7 | 357 | static int |
96ce45ca | 358 | gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, |
1514d34e DJ |
359 | CORE_ADDR address) |
360 | { | |
451fbdda AC |
361 | struct type *vtable_type = gdbarch_data (current_gdbarch, |
362 | vtable_type_gdbarch_data); | |
79d5b63a DJ |
363 | struct value *vtable; |
364 | struct type *vbasetype; | |
1514d34e DJ |
365 | struct value *offset_val, *vbase_array; |
366 | CORE_ADDR vtable_address; | |
367 | long int cur_base_offset, base_offset; | |
1514d34e DJ |
368 | |
369 | /* If it isn't a virtual base, this is easy. The offset is in the | |
370 | type definition. */ | |
371 | if (!BASETYPE_VIA_VIRTUAL (type, index)) | |
372 | return TYPE_BASECLASS_BITPOS (type, index) / 8; | |
373 | ||
374 | /* To access a virtual base, we need to use the vbase offset stored in | |
375 | our vtable. Recent GCC versions provide this information. If it isn't | |
376 | available, we could get what we needed from RTTI, or from drawing the | |
377 | complete inheritance graph based on the debug info. Neither is | |
378 | worthwhile. */ | |
379 | cur_base_offset = TYPE_BASECLASS_BITPOS (type, index) / 8; | |
380 | if (cur_base_offset >= - vtable_address_point_offset ()) | |
8a3fe4f8 | 381 | error (_("Expected a negative vbase offset (old compiler?)")); |
1514d34e DJ |
382 | |
383 | cur_base_offset = cur_base_offset + vtable_address_point_offset (); | |
384 | if ((- cur_base_offset) % TYPE_LENGTH (builtin_type_void_data_ptr) != 0) | |
8a3fe4f8 | 385 | error (_("Misaligned vbase offset.")); |
1514d34e DJ |
386 | cur_base_offset = cur_base_offset |
387 | / ((int) TYPE_LENGTH (builtin_type_void_data_ptr)); | |
388 | ||
389 | /* We're now looking for the cur_base_offset'th entry (negative index) | |
79d5b63a DJ |
390 | in the vcall_and_vbase_offsets array. We used to cast the object to |
391 | its TYPE_VPTR_BASETYPE, and reference the vtable as TYPE_VPTR_FIELDNO; | |
392 | however, that cast can not be done without calling baseclass_offset again | |
393 | if the TYPE_VPTR_BASETYPE is a virtual base class, as described in the | |
394 | v3 C++ ABI Section 2.4.I.2.b. Fortunately the ABI guarantees that the | |
395 | vtable pointer will be located at the beginning of the object, so we can | |
396 | bypass the casting. Verify that the TYPE_VPTR_FIELDNO is in fact at the | |
7ed85d26 DJ |
397 | start of whichever baseclass it resides in, as a sanity measure - iff |
398 | we have debugging information for that baseclass. */ | |
79d5b63a DJ |
399 | |
400 | vbasetype = TYPE_VPTR_BASETYPE (type); | |
7ed85d26 DJ |
401 | if (TYPE_VPTR_FIELDNO (vbasetype) < 0) |
402 | fill_in_vptr_fieldno (vbasetype); | |
403 | ||
404 | if (TYPE_VPTR_FIELDNO (vbasetype) >= 0 | |
405 | && TYPE_FIELD_BITPOS (vbasetype, TYPE_VPTR_FIELDNO (vbasetype)) != 0) | |
8a3fe4f8 | 406 | error (_("Illegal vptr offset in class %s"), |
79d5b63a DJ |
407 | TYPE_NAME (vbasetype) ? TYPE_NAME (vbasetype) : "<unknown>"); |
408 | ||
409 | vtable_address = value_as_address (value_at_lazy (builtin_type_void_data_ptr, | |
00a4c844 | 410 | address)); |
1514d34e | 411 | vtable = value_at_lazy (vtable_type, |
00a4c844 | 412 | vtable_address - vtable_address_point_offset ()); |
1514d34e DJ |
413 | offset_val = value_from_longest(builtin_type_int, cur_base_offset); |
414 | vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets); | |
415 | base_offset = value_as_long (value_subscript (vbase_array, offset_val)); | |
416 | return base_offset; | |
417 | } | |
7ed49443 JB |
418 | |
419 | static void | |
420 | init_gnuv3_ops (void) | |
421 | { | |
030f20e1 | 422 | vtable_type_gdbarch_data = gdbarch_data_register_post_init (build_gdb_vtable_type); |
7ed49443 JB |
423 | |
424 | gnu_v3_abi_ops.shortname = "gnu-v3"; | |
425 | gnu_v3_abi_ops.longname = "GNU G++ Version 3 ABI"; | |
426 | gnu_v3_abi_ops.doc = "G++ Version 3 ABI"; | |
358777b0 EZ |
427 | gnu_v3_abi_ops.is_destructor_name = |
428 | (enum dtor_kinds (*) (const char *))is_gnu_v3_mangled_dtor; | |
429 | gnu_v3_abi_ops.is_constructor_name = | |
430 | (enum ctor_kinds (*) (const char *))is_gnu_v3_mangled_ctor; | |
7ed49443 JB |
431 | gnu_v3_abi_ops.is_vtable_name = gnuv3_is_vtable_name; |
432 | gnu_v3_abi_ops.is_operator_name = gnuv3_is_operator_name; | |
433 | gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type; | |
434 | gnu_v3_abi_ops.virtual_fn_field = gnuv3_virtual_fn_field; | |
1514d34e | 435 | gnu_v3_abi_ops.baseclass_offset = gnuv3_baseclass_offset; |
7ed49443 JB |
436 | } |
437 | ||
b9362cc7 | 438 | extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */ |
7ed49443 JB |
439 | |
440 | void | |
441 | _initialize_gnu_v3_abi (void) | |
442 | { | |
443 | init_gnuv3_ops (); | |
444 | ||
fe1f4a5e | 445 | register_cp_abi (&gnu_v3_abi_ops); |
7ed49443 | 446 | } |