UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
bfd.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 Copyright (C) 1997-2001 Id Software, Inc.
10 
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 
20 See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 
26 */
27 
28 #include "../common/common.h"
29 
30 #ifdef HAVE_BFD_H
31 #include "bfd.h"
32 
33 void output_init (struct output_buffer* ob, char* buf, size_t sz)
34 {
35  ob->buf = buf;
36  ob->sz = sz;
37  ob->ptr = 0;
38  ob->buf[0] = '\0';
39 }
40 
41 void output_print (struct output_buffer* ob, const char* format, ...)
42 {
43  va_list ap;
44  if (ob->sz == ob->ptr)
45  return;
46  ob->buf[ob->ptr] = '\0';
47  va_start(ap, format);
48  vsnprintf(ob->buf + ob->ptr, ob->sz - ob->ptr, format, ap);
49  va_end(ap);
50 
51  ob->ptr = strlen(ob->buf + ob->ptr) + ob->ptr;
52 }
53 
54 static void lookup_section (bfd* abfd, asection* sec, void* opaque_data)
55 {
56  struct find_info* data = (struct find_info*)opaque_data;
57 
58  if (data->func)
59  return;
60 
61  if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
62  return;
63 
64  const bfd_vma vma = bfd_get_section_vma(abfd, sec);
65  if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter)
66  return;
67 
68  bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma,
69  &(data->file), &(data->func), &(data->line));
70 }
71 
72 void find (struct bfd_ctx * b, size_t offset, const char** file, const char** func, unsigned* line)
73 {
74  struct find_info data;
75  data.func = nullptr;
76  data.symbol = b->symbol;
77  data.counter = offset;
78  data.file = nullptr;
79  data.func = nullptr;
80  data.line = 0;
81 
82  bfd_map_over_sections(b->handle, &lookup_section, &data);
83  if (file) {
84  *file = data.file;
85  }
86  if (func) {
87  *func = data.func;
88  }
89  if (line) {
90  *line = data.line;
91  }
92 }
93 
94 static void list_matching_formats (struct output_buffer* ob, const char* procname, char** p)
95 {
96  if (!p || !*p)
97  return;
98 
99  output_print(ob, "%s: Matching formats: ", procname);
100  while (*p)
101  output_print(ob, " %s", *p++);
102  output_print(ob, "\n");
103 }
104 
105 static int init_bfd_ctx (struct bfd_ctx* bc, const char* procname, struct output_buffer* ob)
106 {
107  void* symbol_table;
108  unsigned dummy = 0;
109  char** matching = nullptr;
110 
111  bc->handle = nullptr;
112  bc->symbol = nullptr;
113 
114  bfd* b = bfd_openr(procname, 0);
115  if (!b) {
116  output_print(ob, "Failed to open bfd from (%s)\n", procname);
117  return 1;
118  }
119 
120  if (bfd_check_format(b, bfd_archive)) {
121  output_print(ob, "Cannot get addresses from archive (%s)\n", b->filename);
122  bfd_close(b);
123  return -1;
124  }
125 
126  if (!bfd_check_format_matches(b, bfd_object, &matching)) {
127  const char* errmsg = bfd_errmsg(bfd_get_error());
128  output_print(ob, "%s (%s)\n", errmsg, b->filename);
129  if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
130  list_matching_formats(ob, b->filename, matching);
131  free(matching);
132  }
133  bfd_close(b);
134  return -1;
135  }
136 
137  if ((bfd_get_file_flags(b) & HAS_SYMS) == 0) {
138  const char* errmsg = bfd_errmsg(bfd_get_error());
139  output_print(ob, "Failed to get file flags from (%s) %s\n", b->filename, errmsg);
140  bfd_close(b);
141  return 1;
142  }
143 
144  if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) {
145  if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) {
146  const char* errmsg = bfd_errmsg(bfd_get_error());
147  output_print(ob, "Failed to read symbols from (%s): %s\n", b->filename, errmsg);
148  free(symbol_table);
149  bfd_close(b);
150  return 1;
151  }
152  }
153 
154  bc->handle = b;
155  bc->symbol = (asymbol**)symbol_table;
156 
157  return 0;
158 }
159 
160 static void close_bfd_ctx (struct bfd_ctx* bc)
161 {
162  free(bc->symbol);
163  if (bc->handle) {
164  bfd_close(bc->handle);
165  }
166 }
167 
168 struct bfd_ctx* get_bc (struct output_buffer* ob, struct bfd_set* set, const char* procname)
169 {
170  struct bfd_ctx bc;
171 
172  while (set->name) {
173  if (Q_streq(set->name, procname)) {
174  return set->bc;
175  }
176  set = set->next;
177  }
178  if (init_bfd_ctx(&bc, procname, ob)) {
179  return nullptr;
180  }
181  set->next = (bfd_set*)calloc(1, sizeof(*set));
182  set->bc = (bfd_ctx*)malloc(sizeof(struct bfd_ctx));
183  memcpy(set->bc, &bc, sizeof(bc));
184  set->name = strdup(procname);
185 
186  return set->bc;
187 }
188 
189 void release_set (struct bfd_set* set)
190 {
191  while (set->next) {
192  struct bfd_set* temp = set->next;
193  free(set->name);
194  close_bfd_ctx(set->bc);
195  free(set);
196  set = temp;
197  }
198 }
199 
200 #endif
voidpf void * buf
Definition: ioapi.h:42
void list_matching_formats(char **p)
Definition: addr2line.cpp:109
GLsizei const GLvoid * data
Definition: r_gl.h:152
#define Q_streq(a, b)
Definition: shared.h:136
voidpf uLong offset
Definition: ioapi.h:45
void format(__printf__, 1, 2)))