int bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file) { bfd *iobfd; iobfd = ibfd; if (ibfd->my_archive && !bfd_is_thin_archive (ibfd->my_archive)) iobfd = ibfd->my_archive; file->name = iobfd->filename; if (!iobfd->iostream && !bfd_open_file (iobfd)) return 0; file->fd = fileno ((FILE *) iobfd->iostream); if (iobfd == ibfd) { struct stat stat_buf; if (fstat (file->fd, &stat_buf)) return 0; file->offset = 0; file->filesize = stat_buf.st_size; } else { file->offset = ibfd->origin; file->filesize = arelt_size (ibfd); } return 1; }
bfd_size_type bfd_bwrite (const void *ptr, bfd_size_type size, bfd *abfd) { file_ptr nwrote; while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) abfd = abfd->my_archive; if (abfd->iovec == NULL) { bfd_set_error (bfd_error_invalid_operation); return -1; } nwrote = abfd->iovec->bwrite (abfd, ptr, size); if (nwrote != -1) abfd->where += nwrote; if ((bfd_size_type) nwrote != size) { #ifdef ENOSPC errno = ENOSPC; #endif bfd_set_error (bfd_error_system_call); } return nwrote; }
ufile_ptr bfd_get_file_size (bfd *abfd) { if (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) return arelt_size (abfd); return bfd_get_size (abfd); }
int bfd_flush (bfd *abfd) { while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) abfd = abfd->my_archive; if (abfd->iovec == NULL) return 0; return abfd->iovec->bflush (abfd); }
int bfd_seek (bfd *abfd, file_ptr position, int direction) { int result; ufile_ptr offset = 0; while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) { offset += abfd->origin; abfd = abfd->my_archive; } if (abfd->iovec == NULL) { bfd_set_error (bfd_error_invalid_operation); return -1; } /* For the time being, a BFD may not seek to it's end. The problem is that we don't easily have a way to recognize the end of an element in an archive. */ BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); if (direction != SEEK_CUR) position += offset; if ((direction == SEEK_CUR && position == 0) || (direction == SEEK_SET && (ufile_ptr) position == abfd->where)) return 0; result = abfd->iovec->bseek (abfd, position, direction); if (result != 0) { /* An EINVAL error probably means that the file offset was absurd. */ if (errno == EINVAL) bfd_set_error (bfd_error_file_truncated); else bfd_set_error (bfd_error_system_call); } else { /* Adjust `where' field. */ if (direction == SEEK_CUR) abfd->where += position; else abfd->where = position; } return result; }
/* Returns 0 for success, negative value for failure (in which case bfd_get_error can retrieve the error code). */ int bfd_stat (bfd *abfd, struct stat *statbuf) { int result; while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) abfd = abfd->my_archive; if (abfd->iovec == NULL) { bfd_set_error (bfd_error_invalid_operation); return -1; } result = abfd->iovec->bstat (abfd, statbuf); if (result < 0) bfd_set_error (bfd_error_system_call); return result; }
file_ptr bfd_tell (bfd *abfd) { ufile_ptr offset = 0; file_ptr ptr; while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) { offset += abfd->origin; abfd = abfd->my_archive; } if (abfd->iovec == NULL) return 0; ptr = abfd->iovec->btell (abfd); abfd->where = ptr; return ptr - offset; }
bfd_size_type bfd_bread (void *ptr, bfd_size_type size, bfd *abfd) { file_ptr nread; bfd *element_bfd = abfd; ufile_ptr offset = 0; while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) { offset += abfd->origin; abfd = abfd->my_archive; } /* If this is an archive element, don't read past the end of this element. */ if (element_bfd->arelt_data != NULL) { bfd_size_type maxbytes = arelt_size (element_bfd); if (abfd->where < offset || abfd->where - offset >= maxbytes) { bfd_set_error (bfd_error_invalid_operation); return -1; } if (abfd->where - offset + size > maxbytes) size = maxbytes - (abfd->where - offset); } if (abfd->iovec == NULL) { bfd_set_error (bfd_error_invalid_operation); return -1; } nread = abfd->iovec->bread (abfd, ptr, size); if (nread != -1) abfd->where += nread; return nread; }
void * bfd_mmap (bfd *abfd, void *addr, bfd_size_type len, int prot, int flags, file_ptr offset, void **map_addr, bfd_size_type *map_len) { while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) { offset += abfd->origin; abfd = abfd->my_archive; } if (abfd->iovec == NULL) { bfd_set_error (bfd_error_invalid_operation); return (void *) -1; } return abfd->iovec->bmmap (abfd, addr, len, prot, flags, offset, map_addr, map_len); }
static FILE * bfd_cache_lookup_worker (bfd *abfd, enum cache_flag flag) { bfd *orig_bfd = abfd; if ((abfd->flags & BFD_IN_MEMORY) != 0) abort (); while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) abfd = abfd->my_archive; if (abfd->iostream != NULL) { /* Move the file to the start of the cache. */ if (abfd != bfd_last_cache) { snip (abfd); insert (abfd); } return (FILE *) abfd->iostream; } if (flag & CACHE_NO_OPEN) return NULL; if (bfd_open_file (abfd) == NULL) ; else if (!(flag & CACHE_NO_SEEK) && _bfd_real_fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0 && !(flag & CACHE_NO_SEEK_ERROR)) bfd_set_error (bfd_error_system_call); else return (FILE *) abfd->iostream; /* xgettext:c-format */ _bfd_error_handler (_("reopening %B: %s\n"), orig_bfd, bfd_errmsg (bfd_get_error ())); return NULL; }
file_ptr bfd_tell (bfd *abfd) { file_ptr ptr; if (abfd->iovec) { bfd *parent_bfd = abfd; ptr = abfd->iovec->btell (abfd); while (parent_bfd->my_archive != NULL && !bfd_is_thin_archive (parent_bfd->my_archive)) { ptr -= parent_bfd->origin; parent_bfd = parent_bfd->my_archive; } } else ptr = 0; abfd->where = ptr; return ptr; }
void vfinfo (FILE *fp, const char *fmt, va_list ap, bfd_boolean is_warning) { bfd_boolean fatal = FALSE; const char *scan; int arg_type; unsigned int arg_count = 0; unsigned int arg_no; union vfinfo_args { int i; long l; void *p; bfd_vma v; struct { bfd *abfd; asection *sec; bfd_vma off; } reladdr; enum { Bad, Int, Long, Ptr, Vma, RelAddr } type; } args[9]; for (arg_no = 0; arg_no < sizeof (args) / sizeof (args[0]); arg_no++) args[arg_no].type = Bad; arg_count = 0; scan = fmt; while (*scan != '\0') { while (*scan != '%' && *scan != '\0') scan++; if (*scan == '%') { scan++; arg_no = arg_count; if (*scan != '0' && ISDIGIT (*scan) && scan[1] == '$') { arg_no = *scan - '1'; scan += 2; } arg_type = Bad; switch (*scan++) { case '\0': --scan; break; case 'V': case 'v': case 'W': arg_type = Vma; break; case 's': arg_type = Ptr; break; case 'p': if (*scan == 'A' || *scan == 'B' || *scan == 'I' || *scan == 'R' || *scan == 'S' || *scan == 'T') scan++; arg_type = Ptr; break; case 'C': case 'D': case 'G': case 'H': arg_type = RelAddr; break; case 'd': case 'u': arg_type = Int; break; case 'l': if (*scan == 'd' || *scan == 'u') { ++scan; arg_type = Long; } break; default: break; } if (arg_type != Bad) { if (arg_no >= sizeof (args) / sizeof (args[0])) abort (); args[arg_no].type = arg_type; ++arg_count; } } } for (arg_no = 0; arg_no < arg_count; arg_no++) { switch (args[arg_no].type) { case Int: args[arg_no].i = va_arg (ap, int); break; case Long: args[arg_no].l = va_arg (ap, long); break; case Ptr: args[arg_no].p = va_arg (ap, void *); break; case Vma: args[arg_no].v = va_arg (ap, bfd_vma); break; case RelAddr: args[arg_no].reladdr.abfd = va_arg (ap, bfd *); args[arg_no].reladdr.sec = va_arg (ap, asection *); args[arg_no].reladdr.off = va_arg (ap, bfd_vma); break; default: abort (); } } arg_count = 0; while (*fmt != '\0') { const char *str = fmt; while (*fmt != '%' && *fmt != '\0') fmt++; if (fmt != str) if (fwrite (str, 1, fmt - str, fp)) { /* Ignore. */ } if (*fmt == '%') { fmt++; arg_no = arg_count; if (*fmt != '0' && ISDIGIT (*fmt) && fmt[1] == '$') { arg_no = *fmt - '1'; fmt += 2; } switch (*fmt++) { case '\0': --fmt; /* Fall through. */ case '%': /* literal % */ putc ('%', fp); break; case 'X': /* no object output, fail return */ config.make_executable = FALSE; break; case 'V': /* hex bfd_vma */ { bfd_vma value = args[arg_no].v; ++arg_count; fprintf_vma (fp, value); } break; case 'v': /* hex bfd_vma, no leading zeros */ { char buf[100]; char *p = buf; bfd_vma value = args[arg_no].v; ++arg_count; sprintf_vma (p, value); while (*p == '0') p++; if (!*p) p--; fputs (p, fp); } break; case 'W': /* hex bfd_vma with 0x with no leading zeroes taking up 8 spaces. */ { char buf[100]; bfd_vma value; char *p; int len; value = args[arg_no].v; ++arg_count; sprintf_vma (buf, value); for (p = buf; *p == '0'; ++p) ; if (*p == '\0') --p; len = strlen (p); while (len < 8) { putc (' ', fp); ++len; } fprintf (fp, "0x%s", p); } break; case 'F': /* Error is fatal. */ fatal = TRUE; break; case 'P': /* Print program name. */ fprintf (fp, "%s", program_name); break; case 'E': /* current bfd error or errno */ fprintf (fp, "%s", bfd_errmsg (bfd_get_error ())); break; case 'C': case 'D': case 'G': case 'H': /* Clever filename:linenumber with function name if possible. The arguments are a BFD, a section, and an offset. */ { static bfd *last_bfd; static char *last_file; static char *last_function; bfd *abfd; asection *section; bfd_vma offset; asymbol **asymbols = NULL; const char *filename; const char *functionname; unsigned int linenumber; bfd_boolean discard_last; bfd_boolean done; abfd = args[arg_no].reladdr.abfd; section = args[arg_no].reladdr.sec; offset = args[arg_no].reladdr.off; ++arg_count; if (abfd != NULL) { if (!bfd_generic_link_read_symbols (abfd)) einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd); asymbols = bfd_get_outsymbols (abfd); } /* The GNU Coding Standard requires that error messages be of the form: source-file-name:lineno: message We do not always have a line number available so if we cannot find them we print out the section name and offset instead. */ discard_last = TRUE; if (abfd != NULL && bfd_find_nearest_line (abfd, section, asymbols, offset, &filename, &functionname, &linenumber)) { if (functionname != NULL && (fmt[-1] == 'C' || fmt[-1] == 'H')) { /* Detect the case where we are printing out a message for the same function as the last call to vinfo ("%C"). In this situation do not print out the ABFD filename or the function name again. Note - we do still print out the source filename, as this will allow programs that parse the linker's output (eg emacs) to correctly locate multiple errors in the same source file. */ if (last_bfd == NULL || last_function == NULL || last_bfd != abfd || (last_file == NULL) != (filename == NULL) || (filename != NULL && filename_cmp (last_file, filename) != 0) || strcmp (last_function, functionname) != 0) { lfinfo (fp, _("%pB: in function `%pT':\n"), abfd, functionname); last_bfd = abfd; if (last_file != NULL) free (last_file); last_file = NULL; if (filename) last_file = xstrdup (filename); if (last_function != NULL) free (last_function); last_function = xstrdup (functionname); } discard_last = FALSE; } else lfinfo (fp, "%pB:", abfd); if (filename != NULL) fprintf (fp, "%s:", filename); done = fmt[-1] != 'H'; if (functionname != NULL && fmt[-1] == 'G') lfinfo (fp, "%pT", functionname); else if (filename != NULL && linenumber != 0) fprintf (fp, "%u%s", linenumber, done ? "" : ":"); else done = FALSE; } else { lfinfo (fp, "%pB:", abfd); done = FALSE; } if (!done) lfinfo (fp, "(%pA+0x%v)", section, offset); if (discard_last) { last_bfd = NULL; if (last_file != NULL) { free (last_file); last_file = NULL; } if (last_function != NULL) { free (last_function); last_function = NULL; } } } break; case 'p': if (*fmt == 'A') { /* section name from a section */ asection *sec; bfd *abfd; const char *group = NULL; struct coff_comdat_info *ci; fmt++; sec = (asection *) args[arg_no].p; ++arg_count; abfd = sec->owner; fprintf (fp, "%s", sec->name); if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour && elf_next_in_group (sec) != NULL && (sec->flags & SEC_GROUP) == 0) group = elf_group_name (sec); else if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_coff_flavour && (ci = bfd_coff_get_comdat_section (sec->owner, sec)) != NULL) group = ci->name; if (group != NULL) fprintf (fp, "[%s]", group); } else if (*fmt == 'B') { /* filename from a bfd */ bfd *abfd = (bfd *) args[arg_no].p; fmt++; ++arg_count; if (abfd == NULL) fprintf (fp, "%s generated", program_name); else if (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) fprintf (fp, "%s(%s)", abfd->my_archive->filename, abfd->filename); else fprintf (fp, "%s", abfd->filename); } else if (*fmt == 'I') { /* filename from a lang_input_statement_type */ lang_input_statement_type *i; fmt++; i = (lang_input_statement_type *) args[arg_no].p; ++arg_count; if (i->the_bfd != NULL && i->the_bfd->my_archive != NULL && !bfd_is_thin_archive (i->the_bfd->my_archive)) fprintf (fp, "(%s)%s", i->the_bfd->my_archive->filename, i->local_sym_name); else fprintf (fp, "%s", i->filename); } else if (*fmt == 'R') { /* Print all that's interesting about a relent. */ arelent *relent = (arelent *) args[arg_no].p; fmt++; ++arg_count; lfinfo (fp, "%s+0x%v (type %s)", (*(relent->sym_ptr_ptr))->name, relent->addend, relent->howto->name); } else if (*fmt == 'S') { /* Print script file and linenumber. */ etree_type node; etree_type *tp = (etree_type *) args[arg_no].p; fmt++; ++arg_count; if (tp == NULL) { tp = &node; tp->type.filename = ldlex_filename (); tp->type.lineno = lineno; } if (tp->type.filename != NULL) fprintf (fp, "%s:%u", tp->type.filename, tp->type.lineno); } else if (*fmt == 'T') { /* Symbol name. */ const char *name = (const char *) args[arg_no].p; fmt++; ++arg_count; if (name == NULL || *name == 0) { fprintf (fp, _("no symbol")); break; } else if (demangling) { char *demangled; demangled = bfd_demangle (link_info.output_bfd, name, DMGL_ANSI | DMGL_PARAMS); if (demangled != NULL) { fprintf (fp, "%s", demangled); free (demangled); break; } } fprintf (fp, "%s", name); } else { /* native (host) void* pointer, like printf */ fprintf (fp, "%p", args[arg_no].p); ++arg_count; } break; case 's': /* arbitrary string, like printf */ fprintf (fp, "%s", (char *) args[arg_no].p); ++arg_count; break; case 'd': /* integer, like printf */ fprintf (fp, "%d", args[arg_no].i); ++arg_count; break; case 'u': /* unsigned integer, like printf */ fprintf (fp, "%u", args[arg_no].i); ++arg_count; break; case 'l': if (*fmt == 'd') { fprintf (fp, "%ld", args[arg_no].l); ++arg_count; ++fmt; break; } else if (*fmt == 'u') { fprintf (fp, "%lu", args[arg_no].l); ++arg_count; ++fmt; break; } /* Fallthru */ default: fprintf (fp, "%%%c", fmt[-1]); break; } } } if (is_warning && config.fatal_warnings) config.make_executable = FALSE; if (fatal) xexit (1); }
bfd_boolean bfd_elf64_archive_write_armap (bfd *arch, unsigned int elength, struct orl *map, unsigned int symbol_count, int stridx) { unsigned int ranlibsize = (symbol_count * 8) + 8; unsigned int stringsize = stridx; unsigned int mapsize = stringsize + ranlibsize; file_ptr archive_member_file_ptr; bfd *current = arch->archive_head; unsigned int count; struct ar_hdr hdr; int padding; bfd_byte buf[8]; padding = BFD_ALIGN (mapsize, 8) - mapsize; mapsize += padding; /* work out where the first object file will go in the archive */ archive_member_file_ptr = (mapsize + elength + sizeof (struct ar_hdr) + SARMAG); memset (&hdr, ' ', sizeof (struct ar_hdr)); memcpy (hdr.ar_name, "/SYM64/", strlen ("/SYM64/")); if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) return FALSE; _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", time (NULL)); /* This, at least, is what Intel coff sets the values to.: */ _bfd_ar_spacepad (hdr.ar_uid, sizeof (hdr.ar_uid), "%ld", 0); _bfd_ar_spacepad (hdr.ar_gid, sizeof (hdr.ar_gid), "%ld", 0); _bfd_ar_spacepad (hdr.ar_mode, sizeof (hdr.ar_mode), "%-7lo", 0); memcpy (hdr.ar_fmag, ARFMAG, 2); /* Write the ar header for this item and the number of symbols */ if (bfd_bwrite (&hdr, sizeof (struct ar_hdr), arch) != sizeof (struct ar_hdr)) return FALSE; bfd_putb64 ((bfd_vma) symbol_count, buf); if (bfd_bwrite (buf, 8, arch) != 8) return FALSE; /* Two passes, first write the file offsets for each symbol - remembering that each offset is on a two byte boundary. */ /* Write out the file offset for the file associated with each symbol, and remember to keep the offsets padded out. */ count = 0; for (current = arch->archive_head; current != NULL && count < symbol_count; current = current->archive_next) { /* For each symbol which is used defined in this object, write out the object file's address in the archive. */ for (; count < symbol_count && map[count].u.abfd == current; count++) { bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf); if (bfd_bwrite (buf, 8, arch) != 8) return FALSE; } /* Add size of this archive entry */ archive_member_file_ptr += sizeof (struct ar_hdr); if (! bfd_is_thin_archive (arch)) archive_member_file_ptr += arelt_size (current); /* remember about the even alignment */ archive_member_file_ptr += archive_member_file_ptr % 2; } /* now write the strings themselves */ for (count = 0; count < symbol_count; count++) { size_t len = strlen (*map[count].name) + 1; if (bfd_bwrite (*map[count].name, len, arch) != len) return FALSE; } /* The spec says that this should be padded to an 8 byte boundary. However, the Irix 6.2 tools do not appear to do this. */ while (padding != 0) { if (bfd_bwrite ("", 1, arch) != 1) return FALSE; --padding; } return TRUE; }
bfd_boolean bfd_get_file_window (bfd *abfd, file_ptr offset, bfd_size_type size, bfd_window *windowp, bfd_boolean writable) { static size_t pagesize; bfd_window_internal *i = windowp->i; bfd_size_type size_to_alloc = size; if (debug_windows) fprintf (stderr, "bfd_get_file_window (%p, %6ld, %6ld, %p<%p,%lx,%p>, %d)", abfd, (long) offset, (long) size, windowp, windowp->data, (unsigned long) windowp->size, windowp->i, writable); /* Make sure we know the page size, so we can be friendly to mmap. */ if (pagesize == 0) pagesize = getpagesize (); if (pagesize == 0) abort (); if (i == NULL) { i = bfd_zmalloc (sizeof (bfd_window_internal)); if (i == NULL) return FALSE; i->data = NULL; } #ifdef HAVE_MMAP if (ok_to_map && (i->data == NULL || i->mapped == 1) && (abfd->flags & BFD_IN_MEMORY) == 0) { file_ptr file_offset, offset2; size_t real_size; int fd; /* Find the real file and the real offset into it. */ while (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) { offset += abfd->origin; abfd = abfd->my_archive; } /* Seek into the file, to ensure it is open if cacheable. */ if (abfd->iostream == NULL && (abfd->iovec == NULL || abfd->iovec->bseek (abfd, offset, SEEK_SET) != 0)) goto free_and_fail; fd = fileno ((FILE *) abfd->iostream); /* Compute offsets and size for mmap and for the user's data. */ offset2 = offset % pagesize; if (offset2 < 0) abort (); file_offset = offset - offset2; real_size = offset + size - file_offset; real_size = real_size + pagesize - 1; real_size -= real_size % pagesize; /* If we're re-using a memory region, make sure it's big enough. */ if (i->data != NULL && i->size < size) { munmap (i->data, i->size); i->data = NULL; } i->data = mmap (i->data, real_size, writable ? PROT_WRITE | PROT_READ : PROT_READ, (writable ? MAP_FILE | MAP_PRIVATE : MAP_FILE | MAP_SHARED), fd, file_offset); if (i->data == (void *) -1) { /* An error happened. Report it, or try using malloc, or something. */ bfd_set_error (bfd_error_system_call); windowp->data = 0; if (debug_windows) fprintf (stderr, "\t\tmmap failed!\n"); goto free_and_fail; } if (debug_windows) fprintf (stderr, "\n\tmapped %ld at %p, offset is %ld\n", (long) real_size, i->data, (long) offset2); i->size = real_size; windowp->data = (bfd_byte *) i->data + offset2; windowp->size = size; i->mapped = 1; i->refcount = 1; windowp->i = i; return TRUE; } else if (debug_windows) { if (ok_to_map) fprintf (stderr, _("not mapping: data=%lx mapped=%d\n"), (unsigned long) i->data, (int) i->mapped); else fprintf (stderr, _("not mapping: env var not set\n")); } #else ok_to_map = 0; #endif #ifdef HAVE_MPROTECT if (!writable) { size_to_alloc += pagesize - 1; size_to_alloc -= size_to_alloc % pagesize; } #endif if (debug_windows) fprintf (stderr, "\n\t%s(%6ld)", i->data ? "realloc" : " malloc", (long) size_to_alloc); i->data = bfd_realloc_or_free (i->data, size_to_alloc); if (debug_windows) fprintf (stderr, "\t-> %p\n", i->data); if (i->data == NULL) { if (size_to_alloc == 0) { windowp->i = i; return TRUE; } goto free_and_fail; } i->refcount = 1; if (bfd_seek (abfd, offset, SEEK_SET) != 0) goto free_and_fail; i->size = bfd_bread (i->data, size, abfd); if (i->size != size) goto free_and_fail; i->mapped = 0; #ifdef HAVE_MPROTECT if (!writable) { if (debug_windows) fprintf (stderr, "\tmprotect (%p, %ld, PROT_READ)\n", i->data, (long) i->size); mprotect (i->data, i->size, PROT_READ); } #endif windowp->data = i->data; windowp->size = i->size; windowp->i = i; return TRUE; free_and_fail: /* We have a bfd_window_internal, but an error occurred. Free it. */ free (i); return FALSE; }
static int _bfd_doprnt (FILE *stream, const char *format, union _bfd_doprnt_args *args) { const char *ptr = format; char specifier[128]; int total_printed = 0; unsigned int arg_count = 0; while (*ptr != '\0') { int result; if (*ptr != '%') { /* While we have regular characters, print them. */ char *end = strchr (ptr, '%'); if (end != NULL) result = fprintf (stream, "%.*s", (int) (end - ptr), ptr); else result = fprintf (stream, "%s", ptr); ptr += result; } else if (ptr[1] == '%') { fputc ('%', stream); result = 1; ptr += 2; } else { /* We have a format specifier! */ char *sptr = specifier; int wide_width = 0, short_width = 0; unsigned int arg_no; /* Copy the % and move forward. */ *sptr++ = *ptr++; /* Check for a positional parameter. */ arg_no = -1u; if (*ptr != '0' && ISDIGIT (*ptr) && ptr[1] == '$') { arg_no = *ptr - '1'; ptr += 2; } /* Move past flags. */ while (strchr ("-+ #0'I", *ptr)) *sptr++ = *ptr++; if (*ptr == '*') { int value; unsigned int arg_index; ptr++; arg_index = arg_count; if (*ptr != '0' && ISDIGIT (*ptr) && ptr[1] == '$') { arg_index = *ptr - '1'; ptr += 2; } value = abs (args[arg_index].i); arg_count++; sptr += sprintf (sptr, "%d", value); } else /* Handle explicit numeric value. */ while (ISDIGIT (*ptr)) *sptr++ = *ptr++; /* Precision. */ if (*ptr == '.') { /* Copy and go past the period. */ *sptr++ = *ptr++; if (*ptr == '*') { int value; unsigned int arg_index; ptr++; arg_index = arg_count; if (*ptr != '0' && ISDIGIT (*ptr) && ptr[1] == '$') { arg_index = *ptr - '1'; ptr += 2; } value = abs (args[arg_index].i); arg_count++; sptr += sprintf (sptr, "%d", value); } else /* Handle explicit numeric value. */ while (ISDIGIT (*ptr)) *sptr++ = *ptr++; } while (strchr ("hlL", *ptr)) { switch (*ptr) { case 'h': short_width = 1; break; case 'l': wide_width++; break; case 'L': wide_width = 2; break; default: abort(); } *sptr++ = *ptr++; } /* Copy the type specifier, and NULL terminate. */ *sptr++ = *ptr++; *sptr = '\0'; if ((int) arg_no < 0) arg_no = arg_count; switch (ptr[-1]) { case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': case 'c': { /* Short values are promoted to int, so just copy it as an int and trust the C library printf to cast it to the right width. */ if (short_width) PRINT_TYPE (int, i); else { switch (wide_width) { case 0: PRINT_TYPE (int, i); break; case 1: PRINT_TYPE (long, l); break; case 2: default: #if defined (__MSVCRT__) sptr[-3] = 'I'; sptr[-2] = '6'; sptr[-1] = '4'; *sptr++ = ptr[-1]; *sptr = '\0'; #endif #if defined (__GNUC__) || defined (HAVE_LONG_LONG) PRINT_TYPE (long long, ll); #else /* Fake it and hope for the best. */ PRINT_TYPE (long, l); #endif break; } } } break; case 'f': case 'e': case 'E': case 'g': case 'G': { if (wide_width == 0) PRINT_TYPE (double, d); else { #if defined (__GNUC__) || defined (HAVE_LONG_DOUBLE) PRINT_TYPE (long double, ld); #else /* Fake it and hope for the best. */ PRINT_TYPE (double, d); #endif } } break; case 's': PRINT_TYPE (char *, p); break; case 'p': if (*ptr == 'A') { asection *sec; bfd *abfd; const char *group = NULL; ptr++; sec = (asection *) args[arg_no].p; if (sec == NULL) /* Invoking %pA with a null section pointer is an internal error. */ abort (); abfd = sec->owner; if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour && elf_next_in_group (sec) != NULL && (sec->flags & SEC_GROUP) == 0) group = elf_group_name (sec); if (group != NULL) result = fprintf (stream, "%s[%s]", sec->name, group); else result = fprintf (stream, "%s", sec->name); } else if (*ptr == 'B') { bfd *abfd; ptr++; abfd = (bfd *) args[arg_no].p; if (abfd == NULL) /* Invoking %pB with a null bfd pointer is an internal error. */ abort (); else if (abfd->my_archive && !bfd_is_thin_archive (abfd->my_archive)) result = fprintf (stream, "%s(%s)", abfd->my_archive->filename, abfd->filename); else result = fprintf (stream, "%s", abfd->filename); } else PRINT_TYPE (void *, p); break; default: abort(); } arg_count++; } if (result == -1) return -1; total_printed += result; } return total_printed; }
int bfd_seek (bfd *abfd, file_ptr position, int direction) { int result; file_ptr file_position; /* For the time being, a BFD may not seek to it's end. The problem is that we don't easily have a way to recognize the end of an element in an archive. */ BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); if (direction == SEEK_CUR && position == 0) return 0; if (abfd->my_archive == NULL || bfd_is_thin_archive (abfd->my_archive)) { if (direction == SEEK_SET && (bfd_vma) position == abfd->where) return 0; } else { /* We need something smarter to optimize access to archives. Currently, anything inside an archive is read via the file handle for the archive. Which means that a bfd_seek on one component affects the `current position' in the archive, as well as in any other component. It might be sufficient to put a spike through the cache abstraction, and look to the archive for the file position, but I think we should try for something cleaner. In the meantime, no optimization for archives. */ } file_position = position; if (direction == SEEK_SET) { bfd *parent_bfd = abfd; while (parent_bfd->my_archive != NULL && !bfd_is_thin_archive (parent_bfd->my_archive)) { file_position += parent_bfd->origin; parent_bfd = parent_bfd->my_archive; } } if (abfd->iovec) result = abfd->iovec->bseek (abfd, file_position, direction); else result = -1; if (result != 0) { int hold_errno = errno; /* Force redetermination of `where' field. */ bfd_tell (abfd); /* An EINVAL error probably means that the file offset was absurd. */ if (hold_errno == EINVAL) bfd_set_error (bfd_error_file_truncated); else { bfd_set_error (bfd_error_system_call); errno = hold_errno; } } else { /* Adjust `where' field. */ if (direction == SEEK_SET) abfd->where = position; else abfd->where += position; } return result; }