libdwfl: Sanity check partial core file dyn data read.
[platform/upstream/elfutils.git] / libdw / dwarf_formaddr.c
1 /* Return address represented by attribute.
2    Copyright (C) 2003-2010, 2018 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 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <dwarf.h>
34 #include "libdwP.h"
35
36
37 int
38 __libdw_addrx (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr)
39 {
40   Dwarf_Off addr_off = __libdw_cu_addr_base (cu);
41   if (addr_off == (Dwarf_Off) -1)
42     return -1;
43
44   Dwarf *dbg = cu->dbg;
45   if (dbg->sectiondata[IDX_debug_addr] == NULL)
46     {
47       __libdw_seterrno (DWARF_E_NO_DEBUG_ADDR);
48       return -1;
49     }
50
51   /* The section should at least contain room for one address.  */
52   int address_size = cu->address_size;
53   if (cu->address_size > dbg->sectiondata[IDX_debug_addr]->d_size)
54     {
55     invalid_offset:
56       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
57       return -1;
58     }
59
60   if (addr_off > (dbg->sectiondata[IDX_debug_addr]->d_size
61                   - address_size))
62     goto invalid_offset;
63
64   idx *= address_size;
65   if (idx > (dbg->sectiondata[IDX_debug_addr]->d_size
66              - address_size - addr_off))
67     goto invalid_offset;
68
69   const unsigned char *datap;
70   datap = dbg->sectiondata[IDX_debug_addr]->d_buf + addr_off + idx;
71   if (address_size == 4)
72     *addr = read_4ubyte_unaligned (dbg, datap);
73   else
74     *addr = read_8ubyte_unaligned (dbg, datap);
75
76   return 0;
77 }
78
79 int
80 dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
81 {
82   if (attr == NULL)
83     return -1;
84
85   Dwarf_Word idx;
86   Dwarf_CU *cu = attr->cu;
87   Dwarf *dbg = cu->dbg;
88   const unsigned char *datap = attr->valp;
89   const unsigned char *endp = attr->cu->endp;
90   switch (attr->form)
91     {
92       /* There is one form that just encodes the whole address.  */
93       case DW_FORM_addr:
94         if (__libdw_read_address (dbg, cu_sec_idx (cu), datap,
95                                   cu->address_size, return_addr))
96           return -1;
97         return 0;
98
99       /* All others encode an index into the .debug_addr section where
100          the address can be found.  */
101       case DW_FORM_GNU_addr_index:
102       case DW_FORM_addrx:
103         if (datap >= endp)
104           {
105           invalid:
106             __libdw_seterrno (DWARF_E_INVALID_DWARF);
107             return -1;
108           }
109         get_uleb128 (idx, datap, endp);
110         break;
111
112       case DW_FORM_addrx1:
113         if (datap >= endp - 1)
114           goto invalid;
115         idx = *datap;
116         break;
117
118       case DW_FORM_addrx2:
119         if (datap >= endp - 2)
120           goto invalid;
121         idx = read_2ubyte_unaligned (dbg, datap);
122         break;
123
124       case DW_FORM_addrx3:
125         if (datap >= endp - 3)
126           goto invalid;
127         idx = read_3ubyte_unaligned (dbg, datap);
128         break;
129
130       case DW_FORM_addrx4:
131         if (datap >= endp - 4)
132           goto invalid;
133         idx = read_4ubyte_unaligned (dbg, datap);
134         break;
135
136       default:
137         __libdw_seterrno (DWARF_E_NO_ADDR);
138         return -1;
139     }
140
141   /* So we got an index.  Lets see if it is valid and we can get the actual
142      address.  */
143   if (__libdw_addrx (cu, idx, return_addr) != 0)
144     return -1;
145
146   return 0;
147 }
148 INTDEF(dwarf_formaddr)