v / thirdparty / libbacktrace
Raw file | 818 loc (677 sloc) | 22.05 KB | Latest commit hash 76a735450
1// pecoff.c:
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5
6typedef struct {
7 uint16_t machine;
8 uint16_t number_of_sections;
9 uint32_t time_date_stamp;
10 uint32_t pointer_to_symbol_table;
11 uint32_t number_of_symbols;
12 uint16_t size_of_optional_header;
13 uint16_t characteristics;
14} b_coff_file_header;
15
16typedef struct {
17 uint16_t magic;
18 uint8_t major_linker_version;
19 uint8_t minor_linker_version;
20 uint32_t size_of_code;
21 uint32_t size_of_initialized_data;
22 uint32_t size_of_uninitialized_data;
23 uint32_t address_of_entry_point;
24 uint32_t base_of_code;
25 union {
26 struct {
27 uint32_t base_of_data;
28 uint32_t image_base;
29 } pe;
30 struct {
31 uint64_t image_base;
32 } pep;
33 } u;
34} b_coff_optional_header;
35
36#define PE_MAGIC 0x10b
37#define PEP_MAGIC 0x20b
38
39typedef struct {
40 char name[8];
41 uint32_t virtual_size;
42 uint32_t virtual_address;
43 uint32_t size_of_raw_data;
44 uint32_t pointer_to_raw_data;
45 uint32_t pointer_to_relocations;
46 uint32_t pointer_to_line_numbers;
47 uint16_t number_of_relocations;
48 uint16_t number_of_line_numbers;
49 uint32_t characteristics;
50} b_coff_section_header;
51
52typedef union {
53 char short_name[8];
54 struct {
55 unsigned char zeroes[4];
56 unsigned char off[4];
57 } long_name;
58} b_coff_name;
59
60typedef struct {
61 b_coff_name name;
62 unsigned char value[4];
63 unsigned char section_number[2];
64 unsigned char type[2];
65 unsigned char storage_class;
66 unsigned char number_of_aux_symbols;
67} b_coff_external_symbol;
68
69#define N_TBSHFT 4
70#define IMAGE_SYM_DTYPE_FUNCTION 2
71
72#define SYM_SZ 18
73
74typedef struct {
75 const char *name;
76 uint32_t value;
77 int16_t sec;
78 uint16_t type;
79 uint16_t sc;
80} b_coff_internal_symbol;
81
82static const char *const debug_section_names[DEBUG_MAX] = {
83 ".debug_info", ".debug_line", ".debug_abbrev",
84 ".debug_ranges", ".debug_str", ".debug_addr",
85 ".debug_str_offsets", ".debug_line_str", ".debug_rnglists"};
86
87struct debug_section_info {
88 off_t offset;
89
90 size_t size;
91};
92
93struct coff_symbol {
94 const char *name;
95
96 uintptr_t address;
97};
98
99struct coff_syminfo_data {
100 struct coff_syminfo_data *next;
101
102 struct coff_symbol *symbols;
103
104 size_t count;
105};
106
107static int coff_nodebug(struct backtrace_state *state ATTRIBUTE_UNUSED,
108 uintptr_t pc ATTRIBUTE_UNUSED,
109 backtrace_full_callback callback ATTRIBUTE_UNUSED,
110 backtrace_error_callback error_callback, void *data) {
111 error_callback(data, "no debug info in PE/COFF executable", -1);
112 return 0;
113}
114
115static void coff_nosyms(struct backtrace_state *state ATTRIBUTE_UNUSED,
116 uintptr_t addr ATTRIBUTE_UNUSED,
117 backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
118 backtrace_error_callback error_callback, void *data) {
119 error_callback(data, "no symbol table in PE/COFF executable", -1);
120}
121
122static uint32_t coff_read4(const unsigned char *p) {
123 uint32_t res;
124
125 memcpy(&res, p, 4);
126 return res;
127}
128
129static uint16_t coff_read2(const unsigned char *p) {
130 uint16_t res;
131
132 memcpy(&res, p, sizeof(res));
133 return res;
134}
135
136static size_t coff_short_name_len(const char *name) {
137 int i;
138
139 for (i = 0; i < 8; i++)
140 if (name[i] == 0) return i;
141 return 8;
142}
143
144static int coff_short_name_eq(const char *name, const char *cname) {
145 int i;
146
147 for (i = 0; i < 8; i++) {
148 if (name[i] != cname[i]) return 0;
149 if (name[i] == 0) return 1;
150 }
151 return name[8] == 0;
152}
153
154static int coff_long_name_eq(const char *name, unsigned int off,
155 struct backtrace_view *str_view) {
156 if (off >= str_view->len) return 0;
157 return strcmp(name, (const char *)str_view->data + off) == 0;
158}
159
160static int coff_symbol_compare(const void *v1, const void *v2) {
161 const struct coff_symbol *e1 = (const struct coff_symbol *)v1;
162 const struct coff_symbol *e2 = (const struct coff_symbol *)v2;
163
164 if (e1->address < e2->address)
165 return -1;
166 else if (e1->address > e2->address)
167 return 1;
168 else
169 return 0;
170}
171
172static int coff_expand_symbol(b_coff_internal_symbol *isym,
173 const b_coff_external_symbol *sym,
174 uint16_t sects_num, const unsigned char *strtab,
175 size_t strtab_size) {
176 isym->type = coff_read2(sym->type);
177 isym->sec = coff_read2(sym->section_number);
178 isym->sc = sym->storage_class;
179
180 if (isym->sec > 0 && (uint16_t)isym->sec > sects_num) return -1;
181 if (sym->name.short_name[0] != 0)
182 isym->name = sym->name.short_name;
183 else {
184 uint32_t off = coff_read4(sym->name.long_name.off);
185
186 if (off >= strtab_size) return -1;
187 isym->name = (const char *)strtab + off;
188 }
189 return 0;
190}
191
192static int coff_is_function_symbol(const b_coff_internal_symbol *isym) {
193 return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION && isym->sec > 0;
194}
195
196static int coff_initialize_syminfo(
197 struct backtrace_state *state, uintptr_t base_address, int is_64,
198 const b_coff_section_header *sects, size_t sects_num,
199 const b_coff_external_symbol *syms, size_t syms_size,
200 const unsigned char *strtab, size_t strtab_size,
201 backtrace_error_callback error_callback, void *data,
202 struct coff_syminfo_data *sdata) {
203 size_t syms_count;
204 char *coff_symstr;
205 size_t coff_symstr_len;
206 size_t coff_symbol_count;
207 size_t coff_symbol_size;
208 struct coff_symbol *coff_symbols;
209 struct coff_symbol *coff_sym;
210 char *coff_str;
211 size_t i;
212
213 syms_count = syms_size / SYM_SZ;
214
215 coff_symbol_count = 0;
216 coff_symstr_len = 0;
217 for (i = 0; i < syms_count; ++i) {
218 const b_coff_external_symbol *asym = &syms[i];
219 b_coff_internal_symbol isym;
220
221 if (coff_expand_symbol(&isym, asym, sects_num, strtab, strtab_size) < 0) {
222 error_callback(data, "invalid section or offset in coff symbol", 0);
223 return 0;
224 }
225 if (coff_is_function_symbol(&isym)) {
226 ++coff_symbol_count;
227 if (asym->name.short_name[0] != 0)
228 coff_symstr_len += coff_short_name_len(asym->name.short_name) + 1;
229 }
230
231 i += asym->number_of_aux_symbols;
232 }
233
234 coff_symbol_size = (coff_symbol_count + 1) * sizeof(struct coff_symbol);
235 coff_symbols = ((struct coff_symbol *)backtrace_alloc(state, coff_symbol_size,
236 error_callback, data));
237 if (coff_symbols == NULL) return 0;
238
239 if (coff_symstr_len > 0) {
240 coff_symstr =
241 ((char *)backtrace_alloc(state, coff_symstr_len, error_callback, data));
242 if (coff_symstr == NULL) {
243 backtrace_free(state, coff_symbols, coff_symbol_size, error_callback,
244 data);
245 return 0;
246 }
247 } else
248 coff_symstr = NULL;
249
250 coff_sym = coff_symbols;
251 coff_str = coff_symstr;
252 for (i = 0; i < syms_count; ++i) {
253 const b_coff_external_symbol *asym = &syms[i];
254 b_coff_internal_symbol isym;
255
256 if (coff_expand_symbol(&isym, asym, sects_num, strtab, strtab_size)) {
257 abort();
258 }
259 if (coff_is_function_symbol(&isym)) {
260 const char *name;
261 int16_t secnum;
262
263 if (asym->name.short_name[0] != 0) {
264 size_t len = coff_short_name_len(isym.name);
265 name = coff_str;
266 memcpy(coff_str, isym.name, len);
267 coff_str[len] = 0;
268 coff_str += len + 1;
269 } else
270 name = isym.name;
271
272 if (!is_64) {
273 if (name[0] == '_') name++;
274 }
275
276 secnum = coff_read2(asym->section_number);
277
278 coff_sym->name = name;
279 coff_sym->address = (coff_read4(asym->value) +
280 sects[secnum - 1].virtual_address + base_address);
281 coff_sym++;
282 }
283
284 i += asym->number_of_aux_symbols;
285 }
286
287 coff_sym->name = NULL;
288 coff_sym->address = -1;
289
290 backtrace_qsort(coff_symbols, coff_symbol_count, sizeof(struct coff_symbol),
291 coff_symbol_compare);
292
293 sdata->next = NULL;
294 sdata->symbols = coff_symbols;
295 sdata->count = coff_symbol_count;
296
297 return 1;
298}
299
300static void coff_add_syminfo_data(struct backtrace_state *state,
301 struct coff_syminfo_data *sdata) {
302 if (!state->threaded) {
303 struct coff_syminfo_data **pp;
304
305 for (pp = (struct coff_syminfo_data **)(void *)&state->syminfo_data;
306 *pp != NULL; pp = &(*pp)->next)
307 ;
308 *pp = sdata;
309 } else {
310 while (1) {
311 struct coff_syminfo_data **pp;
312
313 pp = (struct coff_syminfo_data **)(void *)&state->syminfo_data;
314
315 while (1) {
316 struct coff_syminfo_data *p;
317
318 p = backtrace_atomic_load_pointer(pp);
319
320 if (p == NULL) break;
321
322 pp = &p->next;
323 }
324
325 if (__sync_bool_compare_and_swap(pp, NULL, sdata)) break;
326 }
327 }
328}
329
330static int coff_symbol_search(const void *vkey, const void *ventry) {
331 const uintptr_t *key = (const uintptr_t *)vkey;
332 const struct coff_symbol *entry = (const struct coff_symbol *)ventry;
333 uintptr_t addr;
334
335 addr = *key;
336 if (addr < entry->address)
337 return -1;
338 else if (addr >= entry[1].address)
339 return 1;
340 else
341 return 0;
342}
343
344static void coff_syminfo(
345 struct backtrace_state *state, uintptr_t addr,
346 backtrace_syminfo_callback callback,
347 backtrace_error_callback error_callback ATTRIBUTE_UNUSED, void *data) {
348 struct coff_syminfo_data *sdata;
349 struct coff_symbol *sym = NULL;
350
351 if (!state->threaded) {
352 for (sdata = (struct coff_syminfo_data *)state->syminfo_data; sdata != NULL;
353 sdata = sdata->next) {
354 sym = ((struct coff_symbol *)bsearch(&addr, sdata->symbols, sdata->count,
355 sizeof(struct coff_symbol),
356 coff_symbol_search));
357 if (sym != NULL) break;
358 }
359 } else {
360 struct coff_syminfo_data **pp;
361
362 pp = (struct coff_syminfo_data **)(void *)&state->syminfo_data;
363 while (1) {
364 sdata = backtrace_atomic_load_pointer(pp);
365 if (sdata == NULL) break;
366
367 sym = ((struct coff_symbol *)bsearch(&addr, sdata->symbols, sdata->count,
368 sizeof(struct coff_symbol),
369 coff_symbol_search));
370 if (sym != NULL) break;
371
372 pp = &sdata->next;
373 }
374 }
375
376 if (sym == NULL)
377 callback(data, addr, NULL, 0, 0);
378 else
379 callback(data, addr, sym->name, sym->address, 0);
380}
381
382static int coff_add(struct backtrace_state *state, int descriptor,
383 backtrace_error_callback error_callback, void *data,
384 fileline *fileline_fn, int *found_sym, int *found_dwarf) {
385 struct backtrace_view fhdr_view;
386 off_t fhdr_off;
387 int magic_ok;
388 b_coff_file_header fhdr;
389 off_t opt_sects_off;
390 size_t opt_sects_size;
391 unsigned int sects_num;
392 struct backtrace_view sects_view;
393 int sects_view_valid;
394 const b_coff_optional_header *opt_hdr;
395 const b_coff_section_header *sects;
396 struct backtrace_view str_view;
397 int str_view_valid;
398 size_t str_size;
399 off_t str_off;
400 struct backtrace_view syms_view;
401 off_t syms_off;
402 size_t syms_size;
403 int syms_view_valid;
404 unsigned int syms_num;
405 unsigned int i;
406 struct debug_section_info sections[DEBUG_MAX];
407 off_t min_offset;
408 off_t max_offset;
409 struct backtrace_view debug_view;
410 int debug_view_valid;
411 int is_64;
412 uintptr_t image_base;
413 struct dwarf_sections dwarf_sections;
414
415 *found_sym = 0;
416 *found_dwarf = 0;
417
418 sects_view_valid = 0;
419 syms_view_valid = 0;
420 str_view_valid = 0;
421 debug_view_valid = 0;
422
423 if (!backtrace_get_view(state, descriptor, 0, 0x40, error_callback, data,
424 &fhdr_view))
425 goto fail;
426
427 {
428 const unsigned char *vptr = fhdr_view.data;
429
430 if (vptr[0] == 'M' && vptr[1] == 'Z')
431 fhdr_off = coff_read4(vptr + 0x3c);
432 else
433 fhdr_off = 0;
434 }
435
436 backtrace_release_view(state, &fhdr_view, error_callback, data);
437
438 if (!backtrace_get_view(state, descriptor, fhdr_off,
439 sizeof(b_coff_file_header) + 4, error_callback, data,
440 &fhdr_view))
441 goto fail;
442
443 if (fhdr_off != 0) {
444 const char *magic = (const char *)fhdr_view.data;
445 magic_ok = memcmp(magic, "PE\0", 4) == 0;
446 fhdr_off += 4;
447
448 memcpy(&fhdr, fhdr_view.data + 4, sizeof fhdr);
449 } else {
450 memcpy(&fhdr, fhdr_view.data, sizeof fhdr);
451
452 magic_ok = 0;
453 }
454 backtrace_release_view(state, &fhdr_view, error_callback, data);
455
456 if (!magic_ok) {
457 error_callback(data, "executable file is not COFF", 0);
458 goto fail;
459 }
460
461 sects_num = fhdr.number_of_sections;
462 syms_num = fhdr.number_of_symbols;
463
464 opt_sects_off = fhdr_off + sizeof(fhdr);
465 opt_sects_size = (fhdr.size_of_optional_header +
466 sects_num * sizeof(b_coff_section_header));
467
468 if (!backtrace_get_view(state, descriptor, opt_sects_off, opt_sects_size,
469 error_callback, data, §s_view))
470 goto fail;
471 sects_view_valid = 1;
472 opt_hdr = (const b_coff_optional_header *)sects_view.data;
473 sects = (const b_coff_section_header *)(sects_view.data +
474 fhdr.size_of_optional_header);
475
476 is_64 = 0;
477 if (fhdr.size_of_optional_header > sizeof(*opt_hdr)) {
478 if (opt_hdr->magic == PE_MAGIC)
479 image_base = opt_hdr->u.pe.image_base;
480 else if (opt_hdr->magic == PEP_MAGIC) {
481 image_base = opt_hdr->u.pep.image_base;
482 is_64 = 1;
483 } else {
484 error_callback(data, "bad magic in PE optional header", 0);
485 goto fail;
486 }
487 } else
488 image_base = 0;
489
490 if (fhdr.pointer_to_symbol_table == 0) {
491 str_off = 0;
492 str_size = 0;
493 syms_num = 0;
494 syms_size = 0;
495 } else {
496 syms_off = fhdr.pointer_to_symbol_table;
497 syms_size = syms_num * SYM_SZ;
498
499 if (!backtrace_get_view(state, descriptor, syms_off, syms_size + 4,
500 error_callback, data, &syms_view))
501 goto fail;
502 syms_view_valid = 1;
503
504 str_size = coff_read4(syms_view.data + syms_size);
505
506 str_off = syms_off + syms_size;
507
508 if (str_size > 4) {
509 if (!backtrace_get_view(state, descriptor, str_off, str_size,
510 error_callback, data, &str_view))
511 goto fail;
512 str_view_valid = 1;
513 }
514 }
515
516 memset(sections, 0, sizeof sections);
517
518 for (i = 0; i < sects_num; ++i) {
519 const b_coff_section_header *s = sects + i;
520 unsigned int str_off;
521 int j;
522
523 if (s->name[0] == '/') {
524 str_off = atoi(s->name + 1);
525 } else
526 str_off = 0;
527
528 for (j = 0; j < (int)DEBUG_MAX; ++j) {
529 const char *dbg_name = debug_section_names[j];
530 int match;
531
532 if (str_off != 0)
533 match = coff_long_name_eq(dbg_name, str_off, &str_view);
534 else
535 match = coff_short_name_eq(dbg_name, s->name);
536 if (match) {
537 sections[j].offset = s->pointer_to_raw_data;
538 sections[j].size = s->virtual_size <= s->size_of_raw_data
539 ? s->virtual_size
540 : s->size_of_raw_data;
541 break;
542 }
543 }
544 }
545
546 if (syms_num != 0) {
547 struct coff_syminfo_data *sdata;
548
549 sdata = ((struct coff_syminfo_data *)backtrace_alloc(state, sizeof *sdata,
550 error_callback, data));
551 if (sdata == NULL) goto fail;
552
553 if (!coff_initialize_syminfo(state, image_base, is_64, sects, sects_num,
554 syms_view.data, syms_size, str_view.data,
555 str_size, error_callback, data, sdata)) {
556 backtrace_free(state, sdata, sizeof *sdata, error_callback, data);
557 goto fail;
558 }
559
560 *found_sym = 1;
561
562 coff_add_syminfo_data(state, sdata);
563 }
564
565 backtrace_release_view(state, §s_view, error_callback, data);
566 sects_view_valid = 0;
567 if (syms_view_valid) {
568 backtrace_release_view(state, &syms_view, error_callback, data);
569 syms_view_valid = 0;
570 }
571
572 min_offset = 0;
573 max_offset = 0;
574 for (i = 0; i < (int)DEBUG_MAX; ++i) {
575 off_t end;
576
577 if (sections[i].size == 0) continue;
578 if (min_offset == 0 || sections[i].offset < min_offset)
579 min_offset = sections[i].offset;
580 end = sections[i].offset + sections[i].size;
581 if (end > max_offset) max_offset = end;
582 }
583 if (min_offset == 0 || max_offset == 0) {
584 if (!backtrace_close(descriptor, error_callback, data)) goto fail;
585 *fileline_fn = coff_nodebug;
586 return 1;
587 }
588
589 if (!backtrace_get_view(state, descriptor, min_offset,
590 max_offset - min_offset, error_callback, data,
591 &debug_view))
592 goto fail;
593 debug_view_valid = 1;
594
595 if (!backtrace_close(descriptor, error_callback, data)) goto fail;
596 descriptor = -1;
597
598 for (i = 0; i < (int)DEBUG_MAX; ++i) {
599 size_t size = sections[i].size;
600 dwarf_sections.size[i] = size;
601 if (size == 0)
602 dwarf_sections.data[i] = NULL;
603 else
604 dwarf_sections.data[i] = ((const unsigned char *)debug_view.data +
605 (sections[i].offset - min_offset));
606 }
607
608 if (!backtrace_dwarf_add(state, 0, &dwarf_sections, 0, NULL, error_callback,
609 data, fileline_fn, NULL))
610 goto fail;
611
612 *found_dwarf = 1;
613
614 return 1;
615
616fail:
617 if (sects_view_valid)
618 backtrace_release_view(state, §s_view, error_callback, data);
619 if (str_view_valid)
620 backtrace_release_view(state, &str_view, error_callback, data);
621 if (syms_view_valid)
622 backtrace_release_view(state, &syms_view, error_callback, data);
623 if (debug_view_valid)
624 backtrace_release_view(state, &debug_view, error_callback, data);
625 if (descriptor != -1) backtrace_close(descriptor, error_callback, data);
626 return 0;
627}
628
629int backtrace_initialize(struct backtrace_state *state,
630 const char *filename ATTRIBUTE_UNUSED, int descriptor,
631 backtrace_error_callback error_callback, void *data,
632 fileline *fileline_fn) {
633 int ret;
634 int found_sym;
635 int found_dwarf;
636 fileline coff_fileline_fn;
637
638 ret = coff_add(state, descriptor, error_callback, data, &coff_fileline_fn,
639 &found_sym, &found_dwarf);
640 if (!ret) return 0;
641
642 if (!state->threaded) {
643 if (found_sym)
644 state->syminfo_fn = coff_syminfo;
645 else if (state->syminfo_fn == NULL)
646 state->syminfo_fn = coff_nosyms;
647 } else {
648 if (found_sym)
649 backtrace_atomic_store_pointer(&state->syminfo_fn, coff_syminfo);
650 else
651 (void)__sync_bool_compare_and_swap(&state->syminfo_fn, NULL, coff_nosyms);
652 }
653
654 if (!state->threaded) {
655 if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
656 *fileline_fn = coff_fileline_fn;
657 } else {
658 fileline current_fn;
659
660 current_fn = backtrace_atomic_load_pointer(&state->fileline_fn);
661 if (current_fn == NULL || current_fn == coff_nodebug)
662 *fileline_fn = coff_fileline_fn;
663 }
664
665 return 1;
666}
667
668// read.c:
669#include <errno.h>
670#include <stdlib.h>
671#include <sys/types.h>
672#include <unistd.h>
673
674int backtrace_get_view(struct backtrace_state *state, int descriptor,
675 off_t offset, uint64_t size,
676 backtrace_error_callback error_callback, void *data,
677 struct backtrace_view *view) {
678 uint64_t got;
679 ssize_t r;
680
681 if ((uint64_t)(size_t)size != size) {
682 error_callback(data, "file size too large", 0);
683 return 0;
684 }
685
686 if (lseek(descriptor, offset, SEEK_SET) < 0) {
687 error_callback(data, "lseek", errno);
688 return 0;
689 }
690
691 view->base = backtrace_alloc(state, size, error_callback, data);
692 if (view->base == NULL) return 0;
693 view->data = view->base;
694 view->len = size;
695
696 got = 0;
697 while (got < size) {
698 r = read(descriptor, view->base, size - got);
699 if (r < 0) {
700 error_callback(data, "read", errno);
701 free(view->base);
702 return 0;
703 }
704 if (r == 0) break;
705 got += (uint64_t)r;
706 }
707
708 if (got < size) {
709 error_callback(data, "file too short", 0);
710 free(view->base);
711 return 0;
712 }
713
714 return 1;
715}
716
717void backtrace_release_view(struct backtrace_state *state,
718 struct backtrace_view *view,
719 backtrace_error_callback error_callback,
720 void *data) {
721 backtrace_free(state, view->base, view->len, error_callback, data);
722 view->data = NULL;
723 view->base = NULL;
724}
725
726// alloc.c:
727#include <errno.h>
728#include <stdlib.h>
729#include <sys/types.h>
730
731void *backtrace_alloc(struct backtrace_state *state ATTRIBUTE_UNUSED,
732 size_t size, backtrace_error_callback error_callback,
733 void *data) {
734 void *ret;
735
736 ret = malloc(size);
737 if (ret == NULL) {
738 if (error_callback) error_callback(data, "malloc", errno);
739 }
740 return ret;
741}
742
743void backtrace_free(struct backtrace_state *state ATTRIBUTE_UNUSED, void *p,
744 size_t size ATTRIBUTE_UNUSED,
745 backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
746 void *data ATTRIBUTE_UNUSED) {
747 free(p);
748}
749
750void *backtrace_vector_grow(struct backtrace_state *state ATTRIBUTE_UNUSED,
751 size_t size,
752 backtrace_error_callback error_callback, void *data,
753 struct backtrace_vector *vec) {
754 void *ret;
755
756 if (size > vec->alc) {
757 size_t alc;
758 void *base;
759
760 if (vec->size == 0)
761 alc = 32 * size;
762 else if (vec->size >= 4096)
763 alc = vec->size + 4096;
764 else
765 alc = 2 * vec->size;
766
767 if (alc < vec->size + size) alc = vec->size + size;
768
769 base = realloc(vec->base, alc);
770 if (base == NULL) {
771 error_callback(data, "realloc", errno);
772 return NULL;
773 }
774
775 vec->base = base;
776 vec->alc = alc - vec->size;
777 }
778
779 ret = (char *)vec->base + vec->size;
780 vec->size += size;
781 vec->alc -= size;
782 return ret;
783}
784
785void *backtrace_vector_finish(struct backtrace_state *state,
786 struct backtrace_vector *vec,
787 backtrace_error_callback error_callback,
788 void *data) {
789 void *ret;
790
791 if (!backtrace_vector_release(state, vec, error_callback, data)) return NULL;
792 ret = vec->base;
793 vec->base = NULL;
794 vec->size = 0;
795 vec->alc = 0;
796 return ret;
797}
798
799int backtrace_vector_release(struct backtrace_state *state ATTRIBUTE_UNUSED,
800 struct backtrace_vector *vec,
801 backtrace_error_callback error_callback,
802 void *data) {
803 vec->alc = 0;
804
805 if (vec->size == 0) {
806 free(vec->base);
807 vec->base = NULL;
808 return 1;
809 }
810
811 vec->base = realloc(vec->base, vec->size);
812 if (vec->base == NULL) {
813 error_callback(data, "realloc", errno);
814 return 0;
815 }
816
817 return 1;
818}