Merge branch 'master' into merge-job
[deliverable/binutils-gdb.git] / gdb / solib-rocm.c
1 /* Handle ROCm Code Objects for GDB, the GNU Debugger.
2
3 Copyright (C) 2019-2020 Free Software Foundation, Inc.
4 Copyright (C) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (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, see <http://www.gnu.org/licenses/>. */
20
21 #include "defs.h"
22
23 #include "arch-utils.h"
24 #include "elf-bfd.h"
25 #include "gdbcore.h"
26 #include "inferior.h"
27 #include "objfiles.h"
28 #include "observable.h"
29 #include "rocm-tdep.h"
30 #include "solib-svr4.h"
31 #include "solib.h"
32 #include "solist.h"
33 #include "symfile.h"
34
35 #include <functional>
36 #include <string>
37
38 #define ROCM_DSO_NAME_PREFIX "AMDGPU shared object [loaded from memory "
39
40 #define ROCM_DSO_NAME_SUFFIX "]"
41
42 /* ROCm-specific inferior data. */
43
44 struct solib_info
45 {
46 /* List of code objects loaded into the inferior. */
47 struct so_list *solib_list;
48 };
49
50 /* Per-inferior data key. */
51 static const struct inferior_key<solib_info> rocm_solib_data;
52
53 struct target_so_ops rocm_solib_ops;
54
55 /* Free the solib linked list. */
56
57 static void
58 rocm_free_solib_list (struct solib_info *info)
59 {
60 while (info->solib_list != NULL)
61 {
62 struct so_list *next = info->solib_list->next;
63
64 free_so (info->solib_list);
65 info->solib_list = next;
66 }
67
68 info->solib_list = NULL;
69 }
70
71 /* Fetch the solib_info data for the current inferior. */
72
73 static struct solib_info *
74 get_solib_info (void)
75 {
76 struct inferior *inf = current_inferior ();
77
78 struct solib_info *info = rocm_solib_data.get (inf);
79 if (info == NULL)
80 info = rocm_solib_data.emplace (inf);
81
82 return info;
83 }
84
85 /* Relocate section addresses. */
86
87 static void
88 rocm_solib_relocate_section_addresses (struct so_list *so,
89 struct target_section *sec)
90 {
91 if (!rocm_is_amdgcn_gdbarch (gdbarch_from_bfd (so->abfd)))
92 {
93 svr4_so_ops.relocate_section_addresses (so, sec);
94 return;
95 }
96
97 lm_info_svr4 *li = (lm_info_svr4 *)so->lm_info;
98 sec->addr = sec->addr + li->l_addr;
99 sec->endaddr = sec->endaddr + li->l_addr;
100 }
101
102 /* Make a deep copy of the solib linked list. */
103
104 static struct so_list *
105 rocm_solib_copy_list (const struct so_list *src)
106 {
107 struct so_list *dst = NULL;
108 struct so_list **link = &dst;
109
110 while (src != NULL)
111 {
112 struct so_list *newobj;
113
114 newobj = XNEW (struct so_list);
115 memcpy (newobj, src, sizeof (struct so_list));
116
117 lm_info_svr4 *src_li = (lm_info_svr4 *)src->lm_info;
118 newobj->lm_info = new lm_info_svr4 (*src_li);
119
120 newobj->next = NULL;
121 *link = newobj;
122 link = &newobj->next;
123
124 src = src->next;
125 }
126
127 return dst;
128 }
129
130 /* Build a list of `struct so_list' objects describing the shared
131 objects currently loaded in the inferior. */
132
133 static struct so_list *
134 rocm_solib_current_sos (void)
135 {
136 /* First, retrieve the host-side shared library list. */
137 struct so_list *head = svr4_so_ops.current_sos ();
138
139 /* Then, the device-side shared library list. */
140 struct so_list *list = get_solib_info ()->solib_list;
141
142 if (!list)
143 return head;
144
145 list = rocm_solib_copy_list (list);
146
147 if (!head)
148 return list;
149
150 /* Append our libraries to the end of the list. */
151 struct so_list *tail;
152 for (tail = head; tail->next; tail = tail->next)
153 /* Nothing. */;
154 tail->next = list;
155
156 return head;
157 }
158
159 struct target_elf_image
160 {
161 /* The base address of the ELF file image in the inferior's memory. */
162 CORE_ADDR base_addr;
163
164 /* The size of the ELF file image. */
165 ULONGEST size;
166 };
167
168 static void *
169 rocm_bfd_iovec_open (bfd *nbfd, void *open_closure)
170 {
171 return open_closure;
172 }
173
174 static int
175 rocm_bfd_iovec_close (bfd *nbfd, void *stream)
176 {
177 xfree (stream);
178 return 0;
179 }
180
181 static file_ptr
182 rocm_bfd_iovec_pread (bfd *abfd, void *stream, void *buf, file_ptr nbytes,
183 file_ptr offset)
184 {
185 CORE_ADDR addr = ((target_elf_image *)stream)->base_addr;
186
187 if (target_read_memory (addr + offset, (gdb_byte *)buf, nbytes) != 0)
188 {
189 bfd_set_error (bfd_error_invalid_operation);
190 return -1;
191 }
192
193 return nbytes;
194 }
195
196 static int
197 rocm_bfd_iovec_stat (bfd *abfd, void *stream, struct stat *sb)
198 {
199 memset (sb, '\0', sizeof (struct stat));
200 sb->st_size = ((struct target_elf_image *)stream)->size;
201 return 0;
202 }
203
204 static gdb_bfd_ref_ptr
205 rocm_solib_bfd_open (const char *pathname)
206 {
207 struct target_elf_image *open_closure;
208 CORE_ADDR addr, end;
209
210 /* Handle regular SVR4 libraries. */
211 if (strstr (pathname, ROCM_DSO_NAME_PREFIX) != pathname)
212 return svr4_so_ops.bfd_open (pathname);
213
214 /* Decode the start and end addresses. */
215 if (sscanf (pathname + sizeof (ROCM_DSO_NAME_PREFIX) - 1, "0x%lx..0x%lx",
216 &addr, &end)
217 != 2)
218 internal_error (__FILE__, __LINE__, "ROCm-GDB Error: bad DSO name: `%s'",
219 pathname);
220
221 open_closure = XNEW (struct target_elf_image);
222 open_closure->base_addr = addr;
223 open_closure->size = end - addr;
224
225 gdb_bfd_ref_ptr abfd (gdb_bfd_openr_iovec (
226 pathname, "elf64-amdgcn", rocm_bfd_iovec_open, open_closure,
227 rocm_bfd_iovec_pread, rocm_bfd_iovec_close, rocm_bfd_iovec_stat));
228
229 /* Check bfd format. */
230 if (!bfd_check_format (abfd.get (), bfd_object))
231 error (_ ("`%s': not in executable format: %s"),
232 bfd_get_filename (abfd.get ()), bfd_errmsg (bfd_get_error ()));
233
234 unsigned char osabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
235 unsigned char osabiversion = elf_elfheader (abfd)->e_ident[EI_ABIVERSION];
236
237 /* Make a check if the code object in the elf is V3. ROCM-gdb has
238 support only for V3. */
239 if (osabi != ELFOSABI_AMDGPU_HSA)
240 error (_ ("`%s': ELF file OS ABI invalid (%d)."),
241 bfd_get_filename (abfd.get ()), osabi);
242
243 if (osabi == ELFOSABI_AMDGPU_HSA && osabiversion < 1)
244 error (_ ("`%s': ELF file ABI version (%d) is not supported."),
245 bfd_get_filename (abfd.get ()), osabiversion);
246
247 return abfd;
248 }
249
250 static void
251 rocm_solib_create_inferior_hook (int from_tty)
252 {
253 rocm_free_solib_list (get_solib_info ());
254
255 svr4_so_ops.solib_create_inferior_hook (from_tty);
256 }
257
258 static void
259 rocm_update_solib_list ()
260 {
261 amd_dbgapi_process_id_t process_id = get_amd_dbgapi_process_id ();
262 solib_info *info = get_solib_info ();
263 amd_dbgapi_status_t status;
264
265 rocm_free_solib_list (info);
266 struct so_list **link = &info->solib_list;
267
268 amd_dbgapi_code_object_id_t *code_object_list;
269 size_t count;
270
271 if ((status = amd_dbgapi_code_object_list (process_id, &count,
272 &code_object_list, nullptr))
273 != AMD_DBGAPI_STATUS_SUCCESS)
274 {
275 warning (_ ("amd_dbgapi_code_object_list failed (%d)"), status);
276 return;
277 }
278
279 for (size_t i = 0; i < count; ++i)
280 {
281 struct so_list *so = XCNEW (struct so_list);
282 lm_info_svr4 *li = new lm_info_svr4;
283 so->lm_info = li;
284
285 char *uri_bytes;
286
287 if (amd_dbgapi_code_object_get_info (
288 process_id, code_object_list[i],
289 AMD_DBGAPI_CODE_OBJECT_INFO_LOAD_ADDRESS, sizeof (li->l_addr),
290 &li->l_addr)
291 != AMD_DBGAPI_STATUS_SUCCESS
292 || amd_dbgapi_code_object_get_info (
293 process_id, code_object_list[i],
294 AMD_DBGAPI_CODE_OBJECT_INFO_URI_NAME, sizeof (uri_bytes),
295 &uri_bytes)
296 != AMD_DBGAPI_STATUS_SUCCESS)
297 continue;
298
299 /* FIXME: We need to properly decode the URI. */
300
301 std::string uri (uri_bytes);
302 xfree (uri_bytes);
303
304 size_t address_pos = uri.find ("://");
305 if (address_pos == std::string::npos)
306 continue;
307 address_pos += 3;
308
309 size_t fragment_pos = uri.find ('#', address_pos);
310 if (address_pos == std::string::npos)
311 continue;
312
313 std::string fragment = uri.substr (fragment_pos);
314
315 /* Decode the offset and size. */
316 amd_dbgapi_global_address_t mem_addr;
317 amd_dbgapi_size_t mem_size;
318
319 if (sscanf (fragment.c_str (), "#offset=0x%lx&size=0x%lx", &mem_addr,
320 &mem_size)
321 != 2)
322 internal_error (__FILE__, __LINE__,
323 "ROCm-GDB Error: bad DSO name: `%s'", uri.c_str ());
324
325 xsnprintf (so->so_name, sizeof so->so_name,
326 ROCM_DSO_NAME_PREFIX "%s..%s" ROCM_DSO_NAME_SUFFIX,
327 hex_string (mem_addr), hex_string (mem_addr + mem_size));
328 strcpy (so->so_original_name, so->so_name);
329
330 so->next = nullptr;
331 *link = so;
332 link = &so->next;
333 }
334
335 xfree (code_object_list);
336
337 /* Force GDB to reload the solibs. */
338 clear_program_space_solib_cache (current_inferior ()->pspace);
339
340 /* Switch terminal for any messages produced by
341 breakpoint_re_set. */
342 target_terminal::ours_for_output ();
343
344 solib_add (NULL, 0, auto_solib_add);
345
346 /* Switch it back. */
347 target_terminal::inferior ();
348 }
349
350 static void
351 rocm_solib_dbgapi_activated ()
352 {
353 if (rocm_solib_ops.current_sos == NULL)
354 {
355 /* Override what we need to */
356 rocm_solib_ops = svr4_so_ops;
357 rocm_solib_ops.current_sos = rocm_solib_current_sos;
358 rocm_solib_ops.solib_create_inferior_hook
359 = rocm_solib_create_inferior_hook;
360 rocm_solib_ops.bfd_open = rocm_solib_bfd_open;
361 rocm_solib_ops.relocate_section_addresses
362 = rocm_solib_relocate_section_addresses;
363 }
364
365 /* Engage the ROCm so_ops. */
366 set_solib_ops (target_gdbarch (), &rocm_solib_ops);
367 }
368
369 static void
370 rocm_solib_dbgapi_deactivated ()
371 {
372 /* Disengage the ROCm so_ops. */
373 set_solib_ops (target_gdbarch (), &svr4_so_ops);
374 }
375
376 static void
377 rocm_solib_target_inferior_created (struct target_ops *target, int from_tty)
378 {
379 rocm_free_solib_list (get_solib_info ());
380 rocm_update_solib_list ();
381 }
382
383 /* -Wmissing-prototypes */
384 extern initialize_file_ftype _initialize_rocm_solib;
385
386 void
387 _initialize_rocm_solib (void)
388 {
389 /* Install our observers. */
390 amd_dbgapi_activated.attach (rocm_solib_dbgapi_activated);
391 amd_dbgapi_deactivated.attach (rocm_solib_dbgapi_deactivated);
392 amd_dbgapi_code_object_list_updated.attach (rocm_update_solib_list);
393
394 /* FIXME: remove this when we can clear the solist in
395 rocm_solib_create_inferior_hook. */
396 gdb::observers::inferior_created.attach (rocm_solib_target_inferior_created);
397 }
This page took 0.062804 seconds and 4 git commands to generate.