UFO: Alien Invasion
bfd.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2022 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 /* binutils-libs 2.34 compatibility */
34 #ifndef bfd_get_section_flags
35 # define bfd_get_section_flags(bfd, section) (bfd_section_flags(section))
36 #endif
37 
38 #ifndef bfd_get_section_vma
39 # define bfd_get_section_vma(bfd, section) (bfd_section_vma(section))
40 #endif
41 
42 #ifndef bfd_get_section_size
43 # define bfd_get_section_size(section) (bfd_section_size(section))
44 #endif
45 
46 void output_init (struct output_buffer* ob, char* buf, size_t sz)
47 {
48  ob->buf = buf;
49  ob->sz = sz;
50  ob->ptr = 0;
51  ob->buf[0] = '\0';
52 }
53 
54 void output_print (struct output_buffer* ob, const char* format, ...)
55 {
56  va_list ap;
57  if (ob->sz == ob->ptr)
58  return;
59  ob->buf[ob->ptr] = '\0';
60  va_start(ap, format);
61  vsnprintf(ob->buf + ob->ptr, ob->sz - ob->ptr, format, ap);
62  va_end(ap);
63 
64  ob->ptr = strlen(ob->buf + ob->ptr) + ob->ptr;
65 }
66 
67 static void lookup_section (bfd* abfd, asection* sec, void* opaque_data)
68 {
69  struct find_info* data = (struct find_info*)opaque_data;
70 
71  if (data->func)
72  return;
73 
74  if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC))
75  return;
76 
77  const bfd_vma vma = bfd_get_section_vma(abfd, sec);
78  if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter)
79  return;
80 
81  bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma,
82  &(data->file), &(data->func), &(data->line));
83 }
84 
85 void find (struct bfd_ctx * b, size_t offset, const char** file, const char** func, unsigned* line)
86 {
87  struct find_info data;
88  data.func = nullptr;
89  data.symbol = b->symbol;
90  data.counter = offset;
91  data.file = nullptr;
92  data.func = nullptr;
93  data.line = 0;
94 
95  bfd_map_over_sections(b->handle, &lookup_section, &data);
96  if (file) {
97  *file = data.file;
98  }
99  if (func) {
100  *func = data.func;
101  }
102  if (line) {
103  *line = data.line;
104  }
105 }
106 
107 static void list_matching_formats (struct output_buffer* ob, const char* procname, char** p)
108 {
109  if (!p || !*p)
110  return;
111 
112  output_print(ob, "%s: Matching formats: ", procname);
113  while (*p)
114  output_print(ob, " %s", *p++);
115  output_print(ob, "\n");
116 }
117 
118 static int init_bfd_ctx (struct bfd_ctx* bc, const char* procname, struct output_buffer* ob)
119 {
120  void* symbol_table;
121  unsigned dummy = 0;
122  char** matching = nullptr;
123 
124  bc->handle = nullptr;
125  bc->symbol = nullptr;
126 
127  bfd* b = bfd_openr(procname, 0);
128  if (!b) {
129  output_print(ob, "Failed to open bfd from (%s)\n", procname);
130  return 1;
131  }
132 
133  if (bfd_check_format(b, bfd_archive)) {
134  output_print(ob, "Cannot get addresses from archive (%s)\n", b->filename);
135  bfd_close(b);
136  return -1;
137  }
138 
139  if (!bfd_check_format_matches(b, bfd_object, &matching)) {
140  const char* errmsg = bfd_errmsg(bfd_get_error());
141  output_print(ob, "%s (%s)\n", errmsg, b->filename);
142  if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
143  list_matching_formats(ob, b->filename, matching);
144  free(matching);
145  }
146  bfd_close(b);
147  return -1;
148  }
149 
150  if ((bfd_get_file_flags(b) & HAS_SYMS) == 0) {
151  const char* errmsg = bfd_errmsg(bfd_get_error());
152  output_print(ob, "Failed to get file flags from (%s) %s\n", b->filename, errmsg);
153  bfd_close(b);
154  return 1;
155  }
156 
157  if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) {
158  if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) {
159  const char* errmsg = bfd_errmsg(bfd_get_error());
160  output_print(ob, "Failed to read symbols from (%s): %s\n", b->filename, errmsg);
161  free(symbol_table);
162  bfd_close(b);
163  return 1;
164  }
165  }
166 
167  bc->handle = b;
168  bc->symbol = (asymbol**)symbol_table;
169 
170  return 0;
171 }
172 
173 static void close_bfd_ctx (struct bfd_ctx* bc)
174 {
175  free(bc->symbol);
176  if (bc->handle) {
177  bfd_close(bc->handle);
178  }
179 }
180 
181 struct bfd_ctx* get_bc (struct output_buffer* ob, struct bfd_set* set, const char* procname)
182 {
183  struct bfd_ctx bc;
184 
185  while (set->name) {
186  if (Q_streq(set->name, procname)) {
187  return set->bc;
188  }
189  set = set->next;
190  }
191  if (init_bfd_ctx(&bc, procname, ob)) {
192  return nullptr;
193  }
194  set->next = (bfd_set*)calloc(1, sizeof(*set));
195  set->bc = (bfd_ctx*)malloc(sizeof(struct bfd_ctx));
196  memcpy(set->bc, &bc, sizeof(bc));
197  set->name = strdup(procname);
198 
199  return set->bc;
200 }
201 
202 void release_set (struct bfd_set* set)
203 {
204  while (set->next) {
205  struct bfd_set* temp = set->next;
206  free(set->name);
207  close_bfd_ctx(set->bc);
208  free(set);
209  set = temp;
210  }
211 }
212 
213 #endif
QGL_EXTERN GLsizei const GLvoid * data
Definition: r_gl.h:89
voidpf void * buf
Definition: ioapi.h:42
void list_matching_formats(char **p)
Definition: addr2line.cpp:109
#define Q_streq(a, b)
Definition: shared.h:136
voidpf uLong offset
Definition: ioapi.h:45
void format(__printf__, 1, 2)))