packaging: update homepage url
[platform/upstream/elfutils.git] / libdwfl / linux-core-attach.c
1 /* Get Dwarf Frame state for target core file.
2    Copyright (C) 2013, 2014 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11
12    or
13
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17
18    or both in parallel, as here.
19
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28
29 #include "libdwflP.h"
30 #include <fcntl.h>
31 #include "system.h"
32
33 #include "../libdw/memory-access.h"
34
35 #ifndef MIN
36 # define MIN(a, b) ((a) < (b) ? (a) : (b))
37 #endif
38
39 struct core_arg
40 {
41   Elf *core;
42   Elf_Data *note_data;
43   size_t thread_note_offset;
44   Ebl *ebl;
45 };
46
47 struct thread_arg
48 {
49   struct core_arg *core_arg;
50   size_t note_offset;
51 };
52
53 static bool
54 core_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result,
55                   void *dwfl_arg)
56 {
57   Dwfl_Process *process = dwfl->process;
58   struct core_arg *core_arg = dwfl_arg;
59   Elf *core = core_arg->core;
60   assert (core != NULL);
61   static size_t phnum;
62   if (elf_getphdrnum (core, &phnum) < 0)
63     {
64       __libdwfl_seterrno (DWFL_E_LIBELF);
65       return false;
66     }
67   for (size_t cnt = 0; cnt < phnum; ++cnt)
68     {
69       GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
70       if (phdr == NULL || phdr->p_type != PT_LOAD)
71         continue;
72       /* Bias is zero here, a core file itself has no bias.  */
73       GElf_Addr start = __libdwfl_segment_start (dwfl, phdr->p_vaddr);
74       GElf_Addr end = __libdwfl_segment_end (dwfl,
75                                              phdr->p_vaddr + phdr->p_memsz);
76       unsigned bytes = ebl_get_elfclass (process->ebl) == ELFCLASS64 ? 8 : 4;
77       if (addr < start || addr + bytes > end)
78         continue;
79       Elf_Data *data;
80       data = elf_getdata_rawchunk (core, phdr->p_offset + addr - start,
81                                    bytes, ELF_T_ADDR);
82       if (data == NULL)
83         {
84           __libdwfl_seterrno (DWFL_E_LIBELF);
85           return false;
86         }
87       assert (data->d_size == bytes);
88       if (bytes == 8)
89         *result = read_8ubyte_unaligned_noncvt (data->d_buf);
90       else
91         *result = read_4ubyte_unaligned_noncvt (data->d_buf);
92       return true;
93     }
94   __libdwfl_seterrno (DWFL_E_ADDR_OUTOFRANGE);
95   return false;
96 }
97
98 static pid_t
99 core_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
100                   void **thread_argp)
101 {
102   struct core_arg *core_arg = dwfl_arg;
103   Elf *core = core_arg->core;
104   GElf_Nhdr nhdr;
105   size_t name_offset;
106   size_t desc_offset;
107   Elf_Data *note_data = core_arg->note_data;
108   size_t offset;
109
110   struct thread_arg *thread_arg;
111   if (*thread_argp == NULL)
112     {
113       core_arg->thread_note_offset = 0;
114       thread_arg = malloc (sizeof (*thread_arg));
115       if (thread_arg == NULL)
116         {
117           __libdwfl_seterrno (DWFL_E_NOMEM);
118           return -1;
119         }
120       thread_arg->core_arg = core_arg;
121       *thread_argp = thread_arg;
122     }
123   else
124     thread_arg = (struct thread_arg *) *thread_argp;
125
126   while (offset = core_arg->thread_note_offset, offset < note_data->d_size
127          && (core_arg->thread_note_offset = gelf_getnote (note_data, offset,
128                                                           &nhdr, &name_offset,
129                                                           &desc_offset)) > 0)
130     {
131       /* Do not check NAME for now, help broken Linux kernels.  */
132       const char *name = note_data->d_buf + name_offset;
133       const char *desc = note_data->d_buf + desc_offset;
134       GElf_Word regs_offset;
135       size_t nregloc;
136       const Ebl_Register_Location *reglocs;
137       size_t nitems;
138       const Ebl_Core_Item *items;
139       if (! ebl_core_note (core_arg->ebl, &nhdr, name,
140                            &regs_offset, &nregloc, &reglocs, &nitems, &items))
141         {
142           /* This note may be just not recognized, skip it.  */
143           continue;
144         }
145       if (nhdr.n_type != NT_PRSTATUS)
146         continue;
147       const Ebl_Core_Item *item;
148       for (item = items; item < items + nitems; item++)
149         if (strcmp (item->name, "pid") == 0)
150           break;
151       if (item == items + nitems)
152         continue;
153       uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
154       val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
155                 ? be32toh (val32) : le32toh (val32));
156       pid_t tid = (int32_t) val32;
157       eu_static_assert (sizeof val32 <= sizeof tid);
158       thread_arg->note_offset = offset;
159       return tid;
160     }
161
162   free (thread_arg);
163   return 0;
164 }
165
166 static bool
167 core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp)
168 {
169   struct thread_arg *thread_arg = thread_arg_voidp;
170   struct core_arg *core_arg = thread_arg->core_arg;
171   Elf *core = core_arg->core;
172   size_t offset = thread_arg->note_offset;
173   GElf_Nhdr nhdr;
174   size_t name_offset;
175   size_t desc_offset;
176   Elf_Data *note_data = core_arg->note_data;
177   size_t nregs = ebl_frame_nregs (core_arg->ebl);
178   assert (nregs > 0);
179   assert (offset < note_data->d_size);
180   size_t getnote_err = gelf_getnote (note_data, offset, &nhdr, &name_offset,
181                                      &desc_offset);
182   /* __libdwfl_attach_state_for_core already verified the note is there.  */
183   assert (getnote_err != 0);
184   /* Do not check NAME for now, help broken Linux kernels.  */
185   const char *name = note_data->d_buf + name_offset;
186   const char *desc = note_data->d_buf + desc_offset;
187   GElf_Word regs_offset;
188   size_t nregloc;
189   const Ebl_Register_Location *reglocs;
190   size_t nitems;
191   const Ebl_Core_Item *items;
192   int core_note_err = ebl_core_note (core_arg->ebl, &nhdr, name, &regs_offset,
193                                      &nregloc, &reglocs, &nitems, &items);
194   /* __libdwfl_attach_state_for_core already verified the note is there.  */
195   assert (core_note_err != 0);
196   assert (nhdr.n_type == NT_PRSTATUS);
197   const Ebl_Core_Item *item;
198   for (item = items; item < items + nitems; item++)
199     if (strcmp (item->name, "pid") == 0)
200       break;
201   assert (item < items + nitems);
202   pid_t tid;
203   {
204     uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
205     val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
206              ? be32toh (val32) : le32toh (val32));
207     tid = (int32_t) val32;
208     eu_static_assert (sizeof val32 <= sizeof tid);
209   }
210   /* core_next_thread already found this TID there.  */
211   assert (tid == INTUSE(dwfl_thread_tid) (thread));
212   for (item = items; item < items + nitems; item++)
213     if (item->pc_register)
214       break;
215   if (item < items + nitems)
216     {
217       Dwarf_Word pc;
218       switch (gelf_getclass (core) == ELFCLASS32 ? 32 : 64)
219       {
220         case 32:;
221           uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
222           val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
223                    ? be32toh (val32) : le32toh (val32));
224           /* Do a host width conversion.  */
225           pc = val32;
226           break;
227         case 64:;
228           uint64_t val64 = read_8ubyte_unaligned_noncvt (desc + item->offset);
229           val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
230                    ? be64toh (val64) : le64toh (val64));
231           pc = val64;
232           break;
233         default:
234           abort ();
235       }
236       INTUSE(dwfl_thread_state_register_pc) (thread, pc);
237     }
238   desc += regs_offset;
239   for (size_t regloci = 0; regloci < nregloc; regloci++)
240     {
241       const Ebl_Register_Location *regloc = reglocs + regloci;
242       // Iterate even regs out of NREGS range so that we can find pc_register.
243       if (regloc->bits != 32 && regloc->bits != 64)
244         continue;
245       const char *reg_desc = desc + regloc->offset;
246       for (unsigned regno = regloc->regno;
247            regno < regloc->regno + (regloc->count ?: 1U);
248            regno++)
249         {
250           /* PPC provides DWARF register 65 irrelevant for
251              CFI which clashes with register 108 (LR) we need.
252              LR (108) is provided earlier (in NT_PRSTATUS) than the # 65.
253              FIXME: It depends now on their order in core notes.
254              FIXME: It uses private function.  */
255           if (regno < nregs
256               && __libdwfl_frame_reg_get (thread->unwound, regno, NULL))
257             continue;
258           Dwarf_Word val;
259           switch (regloc->bits)
260           {
261             case 32:;
262               uint32_t val32 = read_4ubyte_unaligned_noncvt (reg_desc);
263               reg_desc += sizeof val32;
264               val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
265                        ? be32toh (val32) : le32toh (val32));
266               /* Do a host width conversion.  */
267               val = val32;
268               break;
269             case 64:;
270               uint64_t val64 = read_8ubyte_unaligned_noncvt (reg_desc);
271               reg_desc += sizeof val64;
272               val64 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
273                        ? be64toh (val64) : le64toh (val64));
274               assert (sizeof (*thread->unwound->regs) == sizeof val64);
275               val = val64;
276               break;
277             default:
278               abort ();
279           }
280           /* Registers not valid for CFI are just ignored.  */
281           if (regno < nregs)
282             INTUSE(dwfl_thread_state_registers) (thread, regno, 1, &val);
283           if (regloc->pc_register)
284             INTUSE(dwfl_thread_state_register_pc) (thread, val);
285           reg_desc += regloc->pad;
286         }
287     }
288   return true;
289 }
290
291 static void
292 core_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
293 {
294   struct core_arg *core_arg = dwfl_arg;
295   ebl_closebackend (core_arg->ebl);
296   free (core_arg);
297 }
298
299 static const Dwfl_Thread_Callbacks core_thread_callbacks =
300 {
301   core_next_thread,
302   NULL, /* get_thread */
303   core_memory_read,
304   core_set_initial_registers,
305   core_detach,
306   NULL, /* core_thread_detach */
307 };
308
309 int
310 dwfl_core_file_attach (Dwfl *dwfl, Elf *core)
311 {
312   Dwfl_Error err = DWFL_E_NOERROR;
313   Ebl *ebl = ebl_openbackend (core);
314   if (ebl == NULL)
315     {
316       err = DWFL_E_LIBEBL;
317     fail_err:
318       if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
319         dwfl->attacherr = __libdwfl_canon_error (err);
320       __libdwfl_seterrno (err);
321       return -1;
322     }
323   size_t nregs = ebl_frame_nregs (ebl);
324   if (nregs == 0)
325     {
326       err = DWFL_E_NO_UNWIND;
327     fail:
328       ebl_closebackend (ebl);
329       goto fail_err;
330     }
331   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (core, &ehdr_mem);
332   if (ehdr == NULL)
333     {
334       err = DWFL_E_LIBELF;
335       goto fail;
336     }
337   if (ehdr->e_type != ET_CORE)
338     {
339       err = DWFL_E_NO_CORE_FILE;
340       goto fail;
341     }
342   size_t phnum;
343   if (elf_getphdrnum (core, &phnum) < 0)
344     {
345       err = DWFL_E_LIBELF;
346       goto fail;
347     }
348   pid_t pid = -1;
349   Elf_Data *note_data = NULL;
350   for (size_t cnt = 0; cnt < phnum; ++cnt)
351     {
352       GElf_Phdr phdr_mem, *phdr = gelf_getphdr (core, cnt, &phdr_mem);
353       if (phdr != NULL && phdr->p_type == PT_NOTE)
354         {
355           note_data = elf_getdata_rawchunk (core, phdr->p_offset,
356                                             phdr->p_filesz, ELF_T_NHDR);
357           break;
358         }
359     }
360   if (note_data == NULL)
361     {
362       err = DWFL_E_LIBELF;
363       goto fail;
364     }
365   size_t offset = 0;
366   GElf_Nhdr nhdr;
367   size_t name_offset;
368   size_t desc_offset;
369   while (offset < note_data->d_size
370          && (offset = gelf_getnote (note_data, offset,
371                                     &nhdr, &name_offset, &desc_offset)) > 0)
372     {
373       /* Do not check NAME for now, help broken Linux kernels.  */
374       const char *name = note_data->d_buf + name_offset;
375       const char *desc = note_data->d_buf + desc_offset;
376       GElf_Word regs_offset;
377       size_t nregloc;
378       const Ebl_Register_Location *reglocs;
379       size_t nitems;
380       const Ebl_Core_Item *items;
381       if (! ebl_core_note (ebl, &nhdr, name,
382                            &regs_offset, &nregloc, &reglocs, &nitems, &items))
383         {
384           /* This note may be just not recognized, skip it.  */
385           continue;
386         }
387       if (nhdr.n_type != NT_PRPSINFO)
388         continue;
389       const Ebl_Core_Item *item;
390       for (item = items; item < items + nitems; item++)
391         if (strcmp (item->name, "pid") == 0)
392           break;
393       if (item == items + nitems)
394         continue;
395       uint32_t val32 = read_4ubyte_unaligned_noncvt (desc + item->offset);
396       val32 = (elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB
397                 ? be32toh (val32) : le32toh (val32));
398       pid = (int32_t) val32;
399       eu_static_assert (sizeof val32 <= sizeof pid);
400       break;
401     }
402   if (pid == -1)
403     {
404       /* No valid NT_PRPSINFO recognized in this CORE.  */
405       err = DWFL_E_BADELF;
406       goto fail;
407     }
408   struct core_arg *core_arg = malloc (sizeof *core_arg);
409   if (core_arg == NULL)
410     {
411       err = DWFL_E_NOMEM;
412       goto fail;
413     }
414   core_arg->core = core;
415   core_arg->note_data = note_data;
416   core_arg->thread_note_offset = 0;
417   core_arg->ebl = ebl;
418   if (! INTUSE(dwfl_attach_state) (dwfl, core, pid, &core_thread_callbacks,
419                                    core_arg))
420     {
421       free (core_arg);
422       ebl_closebackend (ebl);
423       return -1;
424     }
425   return pid;
426 }
427 INTDEF (dwfl_core_file_attach)