xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_generic_init.c (revision 4d9fdb46b215739778ebc12079842c9905586999)
1 /*
2   Copyright (C) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
3   Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
4   Portions Copyright 2008-2010 Arxan Technologies, Inc. All rights reserved.
5   Portions Copyright 2011-2019 David Anderson. All rights reserved.
6   Portions Copyright 2012 SN Systems Ltd. All rights reserved.
7 
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of version 2.1 of the GNU Lesser General Public License
10   as published by the Free Software Foundation.
11 
12   This program is distributed in the hope that it would be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16   Further, this software is distributed without any warranty that it is
17   free of the rightful claim of any third person regarding infringement
18   or the like.  Any license provided herein, whether implied or
19   otherwise, applies only to this software file.  Patent licenses, if
20   any, provided herein do not apply to combinations of this program with
21   other software, or any other product whatsoever.
22 
23   You should have received a copy of the GNU Lesser General Public
24   License along with this program; if not, write the Free Software
25   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
26   USA.
27 
28 */
29 
30 #include "config.h"
31 #ifdef HAVE_LIBELF_H
32 #include <libelf.h>
33 #else
34 #ifdef HAVE_LIBELF_LIBELF_H
35 #include <libelf/libelf.h>
36 #endif
37 #endif
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #ifdef HAVE_STDLIB_H
44 #include <stdlib.h>
45 #endif /* HAVE_STDLIB_H */
46 #ifdef HAVE_MALLOC_H
47 /* Useful include for some Windows compilers. */
48 #include <malloc.h>
49 #endif /* HAVE_MALLOC_H */
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #elif defined(_WIN32) && defined(_MSC_VER)
53 #include <io.h>
54 #endif /* HAVE_UNISTD_H */
55 
56 #include "dwarf_incl.h"
57 #include "dwarf_error.h"
58 #include "dwarf_object_detector.h"
59 #include "dwarf_elf_access.h" /* Needed while libelf in use */
60 
61 #ifndef O_BINARY
62 #define O_BINARY 0
63 #endif /* O_BINARY */
64 
65 /*  This is the initialization set intended to
66     handle multiple object formats.
67     Created September 2018
68 
69     The init functions here cannot process archives.
70     For archives the libelf-only dwarf_elf_init*()
71     functions are used if present, else archives
72     cannot be read.
73 */
74 
75 
76 #define DWARF_DBG_ERROR(dbg,errval,retval) \
77     _dwarf_error(dbg, error, errval); return(retval);
78 
79 
80 #define FALSE  0
81 #define TRUE   1
82 /*  An original basic dwarf initializer function for consumers.
83     Return a libdwarf error code on error, return DW_DLV_OK
84     if this succeeds.
85     dwarf_init_b() is a better choice where there
86     are section groups in an object file. */
87 int
dwarf_init(int fd,Dwarf_Unsigned access,Dwarf_Handler errhand,Dwarf_Ptr errarg,Dwarf_Debug * ret_dbg,Dwarf_Error * error)88 dwarf_init(int fd,
89     Dwarf_Unsigned access,
90     Dwarf_Handler errhand,
91     Dwarf_Ptr errarg, Dwarf_Debug * ret_dbg, Dwarf_Error * error)
92 {
93     return dwarf_init_b(fd,access, DW_GROUPNUMBER_ANY,
94         errhand,errarg,ret_dbg,error);
95 }
96 
97 static int
open_a_file(const char * name)98 open_a_file(const char * name)
99 {
100     /* Set to a file number that cannot be legal. */
101     int fd = -1;
102 
103 #if HAVE_ELF_OPEN
104     /*  It is not possible to share file handles
105         between applications or DLLs. Each application has its own
106         file-handle table. For two applications to use the same file
107         using a DLL, they must both open the file individually.
108         Let the 'libelf' dll open and close the file.  */
109     fd = elf_open(name, O_RDONLY | O_BINARY);
110 #else
111     fd = open(name, O_RDONLY | O_BINARY);
112 #endif
113     return fd;
114 }
115 
116 static int
set_global_paths_init(Dwarf_Debug dbg,Dwarf_Error * error)117 set_global_paths_init(Dwarf_Debug dbg, Dwarf_Error* error)
118 {
119     int res = 0;
120 
121     res = dwarf_add_debuglink_global_path(dbg,
122         "/usr/lib/debug",error);
123     return res;
124 }
125 
126 /* New in December 2018. */
dwarf_init_path(const char * path,char * true_path_out_buffer,unsigned true_path_bufferlen,Dwarf_Unsigned access,unsigned groupnumber,Dwarf_Handler errhand,Dwarf_Ptr errarg,Dwarf_Debug * ret_dbg,UNUSEDARG const char * reserved1,UNUSEDARG Dwarf_Unsigned reserved2,UNUSEDARG Dwarf_Unsigned * reserved3,Dwarf_Error * error)127 int dwarf_init_path(const char *path,
128     char *true_path_out_buffer,
129     unsigned true_path_bufferlen,
130     Dwarf_Unsigned    access,
131     unsigned          groupnumber,
132     Dwarf_Handler     errhand,
133     Dwarf_Ptr         errarg,
134     Dwarf_Debug*      ret_dbg,
135     UNUSEDARG const char *       reserved1,
136     UNUSEDARG Dwarf_Unsigned     reserved2,
137     UNUSEDARG Dwarf_Unsigned  *  reserved3,
138     Dwarf_Error*      error)
139 {
140     unsigned       ftype = 0;
141     unsigned       endian = 0;
142     unsigned       offsetsize = 0;
143     Dwarf_Unsigned filesize = 0;
144     int res = 0;
145     int errcode = 0;
146     int fd = -1;
147     Dwarf_Debug dbg = 0;
148     char *file_path = 0;
149 
150     if (!ret_dbg) {
151         DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL,DW_DLV_ERROR);
152     }
153     res = dwarf_object_detector_path(path,
154         true_path_out_buffer,
155         true_path_bufferlen,
156         &ftype,&endian,&offsetsize,&filesize,&errcode);
157     if (res == DW_DLV_NO_ENTRY) {
158         return res;
159     }
160     if (res == DW_DLV_ERROR) {
161         DWARF_DBG_ERROR(NULL, errcode, DW_DLV_ERROR);
162     }
163     if (true_path_out_buffer) {
164         file_path = true_path_out_buffer;
165         fd = open_a_file(true_path_out_buffer);
166     } else {
167         file_path = (char *)path;
168         fd = open_a_file(path);
169     }
170     if(fd == -1) {
171         DWARF_DBG_ERROR(NULL, DW_DLE_FILE_UNAVAILABLE,
172             DW_DLV_ERROR);
173     }
174     switch(ftype) {
175     case DW_FTYPE_ELF: {
176         res = _dwarf_elf_nlsetup(fd,
177             file_path,
178             ftype,endian,offsetsize,filesize,
179             access,groupnumber,errhand,errarg,&dbg,error);
180         if (res != DW_DLV_OK) {
181             *ret_dbg = dbg;
182             close(fd);
183             return res;
184         }
185         dbg->de_path = strdup(file_path);
186         dbg->de_fd = fd;
187         dbg->de_owns_fd = TRUE;
188         res = set_global_paths_init(dbg,error);
189         *ret_dbg = dbg;
190         return res;
191     }
192     case DW_FTYPE_MACH_O: {
193         res = _dwarf_macho_setup(fd,
194             file_path,
195             ftype,endian,offsetsize,filesize,
196             access,groupnumber,errhand,errarg,&dbg,error);
197         if (res != DW_DLV_OK) {
198             close(fd);
199             *ret_dbg = dbg;
200             return res;
201         }
202         dbg->de_path = strdup(file_path);
203         dbg->de_fd = fd;
204         dbg->de_owns_fd = TRUE;
205         set_global_paths_init(dbg,error);
206         *ret_dbg = dbg;
207         return res;
208     }
209     case DW_FTYPE_PE: {
210         res = _dwarf_pe_setup(fd,
211             file_path,
212             ftype,endian,offsetsize,filesize,
213             access,groupnumber,errhand,errarg,&dbg,error);
214         if (res != DW_DLV_OK) {
215             close(fd);
216             *ret_dbg = dbg;
217         }
218         dbg->de_path = strdup(file_path);
219         dbg->de_fd = fd;
220         dbg->de_owns_fd = TRUE;
221         set_global_paths_init(dbg,error);
222         *ret_dbg = dbg;
223         return res;
224     }
225     default:
226         close(fd);
227         DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR);
228     }
229     return DW_DLV_NO_ENTRY; /* placeholder for now */
230 }
231 
232 
233 /*  New March 2017, this provides for reading
234     object files with multiple elf section groups.  */
235 int
dwarf_init_b(int fd,Dwarf_Unsigned access,unsigned group_number,Dwarf_Handler errhand,Dwarf_Ptr errarg,Dwarf_Debug * ret_dbg,Dwarf_Error * error)236 dwarf_init_b(int fd,
237     Dwarf_Unsigned access,
238     unsigned  group_number,
239     Dwarf_Handler errhand,
240     Dwarf_Ptr errarg,
241     Dwarf_Debug * ret_dbg,
242     Dwarf_Error * error)
243 {
244     unsigned ftype = 0;
245     unsigned endian = 0;
246     unsigned offsetsize = 0;
247     Dwarf_Unsigned   filesize = 0;
248     int res = 0;
249     int errcode = 0;
250 
251     if (!ret_dbg) {
252         DWARF_DBG_ERROR(NULL,DW_DLE_DWARF_INIT_DBG_NULL,DW_DLV_ERROR);
253     }
254     res = dwarf_object_detector_fd(fd, &ftype,
255         &endian,&offsetsize,&filesize,&errcode);
256     if (res == DW_DLV_NO_ENTRY) {
257         return res;
258     } else if (res == DW_DLV_ERROR) {
259         DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR);
260     }
261 
262     switch(ftype) {
263     case DW_FTYPE_ELF: {
264         int res2 = 0;
265 
266         res2 = _dwarf_elf_nlsetup(fd,"",
267             ftype,endian,offsetsize,filesize,
268             access,group_number,errhand,errarg,ret_dbg,error);
269         if (res2 != DW_DLV_OK) {
270             return res2;
271         }
272         set_global_paths_init(*ret_dbg,error);
273         return res2;
274         }
275     case DW_FTYPE_MACH_O: {
276         int resm = 0;
277 
278         resm = _dwarf_macho_setup(fd,"",
279             ftype,endian,offsetsize,filesize,
280             access,group_number,errhand,errarg,ret_dbg,error);
281         if (resm != DW_DLV_OK) {
282             return resm;
283         }
284         set_global_paths_init(*ret_dbg,error);
285         return resm;
286         }
287 
288     case DW_FTYPE_PE: {
289         int resp = 0;
290 
291         resp = _dwarf_pe_setup(fd,
292             "",
293             ftype,endian,offsetsize,filesize,
294             access,group_number,errhand,errarg,ret_dbg,error);
295         if (resp != DW_DLV_OK) {
296             return resp;
297         }
298         set_global_paths_init(*ret_dbg,error);
299         return resp;
300         }
301     }
302     DWARF_DBG_ERROR(NULL, DW_DLE_FILE_WRONG_TYPE, DW_DLV_ERROR);
303     return res;
304 }
305 
306 /*
307     Frees all memory that was not previously freed
308     by dwarf_dealloc.
309     Aside from certain categories.
310 
311     Applicable when dwarf_init() or dwarf_elf_init()
312     or the -b() form was used to init 'dbg'.
313 */
314 int
dwarf_finish(Dwarf_Debug dbg,Dwarf_Error * error)315 dwarf_finish(Dwarf_Debug dbg, Dwarf_Error * error)
316 {
317     if(!dbg) {
318         DWARF_DBG_ERROR(NULL, DW_DLE_DBG_NULL, DW_DLV_ERROR);
319     }
320     if (dbg->de_obj_file) {
321         /*  The initial character of a valid
322             dbg->de_obj_file->object struct is a letter:
323             E, F, M, or P */
324         char otype  = *(char *)(dbg->de_obj_file->object);
325 
326         switch(otype) {
327         case 'E':
328 #ifdef DWARF_WITH_LIBELF
329             dwarf_elf_object_access_finish(dbg->de_obj_file);
330 #endif /* DWARF_WITH_LIBELF */
331             break;
332         case 'F':
333             /* Non-libelf elf access */
334             _dwarf_destruct_elf_nlaccess(dbg->de_obj_file);
335             break;
336         case 'M':
337             _dwarf_destruct_macho_access(dbg->de_obj_file);
338             break;
339         case 'P':
340             _dwarf_destruct_pe_access(dbg->de_obj_file);
341             break;
342         default:
343             /*  Do nothing. A serious internal error */
344             break;
345         }
346     }
347     if (dbg->de_owns_fd) {
348         close(dbg->de_fd);
349         dbg->de_owns_fd = FALSE;
350     }
351     free((void *)dbg->de_path);
352     dbg->de_path = 0;
353     /*  dwarf_object_finish() also frees de_path,
354         but that is safe because we set it to zero
355         here so no duplicate free will occur.
356         Not all code uses libdwarf exactly as we do
357         hence the free() there. */
358     return dwarf_object_finish(dbg, error);
359 }
360 
361 /*
362     tieddbg should be the executable or .o
363     that has the .debug_addr section that
364     the base dbg refers to. See Split Objects in DWARF5.
365 
366     Allows setting to NULL (NULL is the default
367     of  de_tied_data.td_tied_object).
368     New September 2015.
369 */
370 int
dwarf_set_tied_dbg(Dwarf_Debug dbg,Dwarf_Debug tieddbg,Dwarf_Error * error)371 dwarf_set_tied_dbg(Dwarf_Debug dbg, Dwarf_Debug tieddbg,Dwarf_Error*error)
372 {
373     if(!dbg) {
374         DWARF_DBG_ERROR(NULL, DW_DLE_DBG_NULL, DW_DLV_ERROR);
375     }
376     dbg->de_tied_data.td_tied_object = tieddbg;
377     if (tieddbg) {
378         tieddbg->de_tied_data.td_is_tied_object = TRUE;
379     }
380     return DW_DLV_OK;
381 }
382 
383 /*  Unsure of the use-case of this.
384     New September 2015. */
385 int
dwarf_get_tied_dbg(Dwarf_Debug dbg,Dwarf_Debug * tieddbg_out,UNUSEDARG Dwarf_Error * error)386 dwarf_get_tied_dbg(Dwarf_Debug dbg, Dwarf_Debug *tieddbg_out,
387     UNUSEDARG Dwarf_Error*error)
388 {
389     *tieddbg_out = dbg->de_tied_data.td_tied_object;
390     return DW_DLV_OK;
391 }
392