aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
Diffstat (limited to 'binutils')
-rw-r--r--binutils/ar.c850
-rw-r--r--binutils/bucomm.c151
-rw-r--r--binutils/filemode.c193
-rw-r--r--binutils/i960-pinsn.c820
-rw-r--r--binutils/m68k-pinsn.c806
-rw-r--r--binutils/nm.c387
-rw-r--r--binutils/objdump.c714
-rw-r--r--binutils/size.c320
-rw-r--r--binutils/sparc-pinsn.c490
-rw-r--r--binutils/version.c5
10 files changed, 4736 insertions, 0 deletions
diff --git a/binutils/ar.c b/binutils/ar.c
new file mode 100644
index 0000000..9a8a528
--- /dev/null
+++ b/binutils/ar.c
@@ -0,0 +1,850 @@
+
+
+
+/* ar.c - Archive modify and extract. */
+/*
+ Bugs: should use getopt the way tar does (complete w/optional -) and
+ should have long options too. GNU ar used to check file against filesystem
+ in quick_update and replace operations (would check mtime). Doesn't warn
+ when name truncated. No way to specify pos_end. Error messages should be
+ more consistant.
+*/
+#include "sysdep.h"
+#include "bfd.h"
+#include "ar.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <errno.h>
+#define BUFSIZE 8192
+/* Not great to have these here. Should they be exported or not? */
+PROTO(size_t, bfd_read, (void *ptr, size_t size, size_t nitems, bfd * abfd));
+PROTO(size_t, bfd_write, (void *ptr, size_t size, size_t nitems, bfd * abfd));
+/* PROTO (void, open_inarch, (char *archive_filename)); */
+#ifdef __STDC__
+static void open_inarch(char *archive_filename);
+#else
+static void open_inarch();
+#endif /* __STDC__ */
+
+PROTO(void, map_over_members, (void (*function) (), char **files, int count));
+PROTO(void, print_contents, (bfd * member));
+PROTO(void, extract_file, (bfd * abfd));
+PROTO(void, delete_members, (char **files_to_delete));
+PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
+PROTO(void, move_members, (char **files_to_move));
+PROTO(void, replace_members, (char **files_to_replace));
+PROTO(void, print_descr, (bfd * abfd));
+PROTO(void, ranlib_only, (char *archname));
+
+/** Globals and flags */
+
+char *program_name = NULL;
+bfd bogus_archive;
+bfd *inarch; /* The input arch we're manipulating */
+
+/* Nonzero means don't warn about creating the archive file if necessary. */
+int silent_create = 0;
+/* Nonzero means describe each action performed. */
+int verbose = 0;
+/* Nonzero means preserve dates of members when extracting them. */
+int preserve_dates = 0;
+/*
+ Nonzero means don't replace existing members whose dates are more recent
+ than the corresponding files.
+*/
+int newer_only = 0;
+/* write a __.SYMDEF member into the modified archive. */
+boolean write_armap = false;
+/*
+ Nonzero means don't update __.SYMDEF unless command line explicitly
+ requested it
+*/
+int ignore_symdef = 0;
+/*
+ Nonzero means it's the name of an existing member; position new or moved
+ files with respect to this one.
+*/
+char *posname = NULL;
+/*
+ Sez how to use `posname': pos_before means position before that member.
+ pos_after means position after that member. pos_end means always at end.
+ pos_default means default appropriately. For the latter two, `posname'
+ should also be zero.
+*/
+enum pos {
+ pos_default, pos_before, pos_after, pos_end
+} postype = pos_default;
+
+/*
+ The option parsing should be in its own function. It will be when I have
+ getopt working.
+*/
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *arg_ptr;
+ char c;
+ enum {
+ none = 0, delete, replace, print_table,
+ print_files, extract, move, quick_append
+ } operation = none;
+ int arg_index;
+ char **files;
+ char *inarch_filename;
+ char *temp;
+ program_name = argv[0];
+
+
+ temp = strrchr(program_name, '/');
+ if (temp == (char *) NULL)
+ temp = program_name; /* shouldn't happen, but... */
+ else
+ ++temp;
+ if (!strcmp(temp, "ranlib")) {
+ if (argc < 2)
+ fatal("Too few command arguments.");
+ ranlib_only(argv[1]);
+ }
+
+
+ if (argc < 3)
+ fatal("Too few command arguments.");
+
+ arg_ptr = argv[1];
+
+ if (*arg_ptr == '-')
+ ++arg_ptr; /* compatibility */
+
+ while (c = *arg_ptr++) {
+ switch (c) {
+ case 'd':
+ case 'm':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 't':
+ case 'x':
+ if (operation != none)
+ fatal("two different operation switches specified");
+ switch (c) {
+ case 'd':
+ operation = delete;
+ break;
+ case 'm':
+ operation = move;
+ break;
+ case 'p':
+ operation = print_files;
+ break;
+ case 'q':
+ operation = quick_append;
+ break;
+ case 'r':
+ operation = replace;
+ break;
+ case 't':
+ operation = print_table;
+ break;
+ case 'x':
+ operation = extract;
+ break;
+ }
+ case 'l':
+ break;
+ case 'c':
+ silent_create = 1;
+ break;
+ case 'o':
+ preserve_dates = 1;
+ break;
+ case 's':
+ write_armap = true;
+ break;
+ case 'u':
+ newer_only = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'a':
+ postype = pos_after;
+ break;
+ case 'b':
+ postype = pos_before;
+ break;
+ case 'i':
+ postype = pos_before;
+ break;
+ default:
+ fatal("invalid option %c", c);
+ }
+ }
+
+ if (operation == none && write_armap)
+ ranlib_only(argv[2]);
+
+ if (operation == none)
+ fatal("no operation specified");
+
+ if (newer_only && operation != replace)
+ fatal("'u' only meaningful with 'r' option.");
+
+ arg_index = 2;
+
+ if (postype != pos_default)
+ posname = argv[arg_index++];
+
+ inarch_filename = argv[arg_index++];
+
+ if (arg_index < argc) {
+ files = argv + arg_index;
+ while (arg_index < argc)
+ if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
+ ignore_symdef = 1;
+ break;
+ }
+ }
+ else
+ files = NULL;
+
+ if (operation == quick_append) {
+ if (files != NULL)
+ do_quick_append(inarch_filename, files);
+ exit(0);
+ }
+
+
+ open_inarch(inarch_filename);
+ /*
+ If we have no archive, and we've been asked to replace then create one
+ */
+
+ if (operation == replace &&
+ inarch == &bogus_archive) {
+ silent_create = 1;
+ do_quick_append(inarch_filename, 0);
+ open_inarch(inarch_filename);
+ }
+
+ switch (operation) {
+
+ case print_table:
+ map_over_members(print_descr, files, argc - 3);
+ break;
+
+ case print_files:
+ map_over_members(print_contents, files, argc - 3);
+ break;
+
+ case extract:
+ map_over_members(extract_file, files, argc - 3);
+ break;
+
+ case delete:
+ if (files != NULL)
+ delete_members(files);
+ break;
+
+ case move:
+ if (files != NULL)
+ move_members(files);
+ break;
+
+ case replace:
+ if (files != NULL || write_armap)
+ replace_members(files);
+ break;
+
+ /* Shouldn't happen! */
+ default:
+ fprintf(stderr, "Sorry; this option not implemented.\n");
+ }
+
+ return (0);
+} /* main() */
+
+static
+char *normalize(file)
+char *file;
+{
+ char * filename = strrchr(file, '/');
+ if (filename != (char *)NULL) {
+ filename ++;
+ }
+ else {
+ filename = file;
+ }
+ return filename;
+}
+
+static void
+open_inarch(archive_filename)
+ char *archive_filename;
+{
+ bfd **last_one;
+ bfd *next_one;
+ struct stat sbuf;
+ bfd_error = no_error;
+ if (stat(archive_filename, &sbuf) != 0) {
+ if (errno != ENOENT)
+ bfd_fatal(archive_filename);
+ if (!silent_create)
+ fprintf(stderr,
+ "%s: creating %s\n", program_name, archive_filename);
+
+ inarch = &bogus_archive;
+ inarch->filename = archive_filename;
+ inarch->has_armap = true;
+
+ }
+ else {
+ inarch = bfd_openr(archive_filename, NULL);
+ if (inarch == NULL) {
+ bloser:
+ bfd_perror(archive_filename);
+ exit(1);
+ }
+
+ if (bfd_check_format(inarch, bfd_archive) != true)
+ fatal("File %s is not an archive.", archive_filename);
+ last_one = &(inarch->next);
+ /* Read all the contents right away, regardless. */
+ for (next_one = bfd_openr_next_archived_file(inarch, NULL);
+ next_one;
+ next_one = bfd_openr_next_archived_file(inarch, next_one)) {
+ *last_one = next_one;
+ last_one = &next_one->next;
+ }
+ *last_one = (bfd *) NULL;
+ if (bfd_error != no_more_archived_files)
+ goto bloser;
+ }
+}
+
+
+
+/*
+ If count is 0, then function is called once on each entry. if nonzero,
+ count is the length of the files chain; function is called on each entry
+ whose name matches one in files
+*/
+void
+map_over_members(function, files, count)
+ void (*function) ();
+ char **files;
+ int count;
+{
+ bfd *head;
+
+
+
+
+ if (count == 0) {
+ for (head = inarch->next; head; head = head->next)
+ function(head);
+ return;
+ }
+ /*
+ This may appear to be a baroque way of accomplishing what we want.
+ however we have to iterate over the filenames in order to notice where
+ a filename is requested but does not exist in the archive. Ditto
+ mapping over each file each time -- we want to hack multiple
+ references.
+ */
+
+ for (; count > 0; files++, count--) {
+ boolean found = false;
+ for (head = inarch->next; head; head = head->next)
+ if ((head->filename != NULL) &&
+ (!strcmp(*files, head->filename))) {
+ found = true;
+ function(head);
+ }
+ if (!found)
+ fprintf(stderr, "No entry %s in archive.\n", *files);
+ }
+}
+
+
+/* Things which are interesting to map over all or some of the files: */
+
+void
+print_descr(abfd)
+ bfd *abfd;
+{
+ print_arelt_descr(abfd, verbose);
+}
+
+void
+print_contents(abfd)
+ bfd *abfd;
+{
+ int ncopied = 0;
+ struct stat buf;
+ long size;
+ if (bfd_stat_arch_elt(abfd, &buf) != 0)
+ fatal("Internal stat error on %s", abfd->filename);
+
+ if (verbose)
+ printf("\n<member %s>\n\n", abfd->filename);
+
+ bfd_seek(abfd, 0, SEEK_SET);
+
+ size = buf.st_size;
+ while (ncopied < size) {
+ char cbuf[BUFSIZE];
+ int nread;
+ int tocopy = size - ncopied;
+ if (tocopy > BUFSIZE)
+ tocopy = BUFSIZE;
+
+ nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
+ abstraction! */
+
+ if (nread != tocopy)
+ fatal("file %s not a valid archive", abfd->my_archive->filename);
+ fwrite(cbuf, 1, nread, stdout);
+ ncopied += tocopy;
+ }
+}
+
+
+/*
+ Extract a member of the archive into its own file.
+
+We defer opening the new file until after we have read a BUFSIZ chunk of the
+ old one, since we know we have just read the archive header for the old
+ one. Since most members are shorter than BUFSIZ, this means we will read
+ the old header, read the old data, write a new inode for the new file, and
+ write the new data, and be done. This 'optimization' is what comes from
+ sitting next to a bare disk and hearing it every time it seeks. -- Gnu
+ Gilmore
+*/
+
+void
+extract_file(abfd)
+ bfd *abfd;
+{
+ FILE *ostream;
+ char cbuf[BUFSIZE];
+ int nread,
+ tocopy;
+ int ncopied = 0;
+ long size;
+ struct stat buf;
+ if (bfd_stat_arch_elt(abfd, &buf) != 0)
+ fatal("Internal stat error on %s", abfd->filename);
+ size = buf.st_size;
+
+ if (verbose)
+ printf("x - %s\n", abfd->filename);
+
+ bfd_seek(abfd, 0, SEEK_SET);
+
+ ostream = 0;
+ while (ncopied < size) {
+ tocopy = size - ncopied;
+ if (tocopy > BUFSIZE)
+ tocopy = BUFSIZE;
+
+ nread = bfd_read(cbuf, 1, tocopy, abfd);
+ if (nread != tocopy)
+ fatal("file %s not a valid archive", abfd->my_archive->filename);
+
+ /* See comment above; this saves disk arm motion */
+ if (!ostream) {
+ /* Seems like an abstraction violation, eh? Well it's OK! */
+ ostream = fopen(abfd->filename, "w");
+ if (!ostream) {
+ perror(abfd->filename);
+ exit(1);
+ }
+ }
+ /* no need to byte-swap; the two formats are presumably compatible(!) */
+ fwrite(cbuf, 1, nread, ostream);
+ ncopied += tocopy;
+ }
+
+ fclose(ostream);
+ chmod(abfd->filename, buf.st_mode);
+
+ if (preserve_dates) {
+#ifdef USG
+ long tb[2];
+ tb[0] = buf.st_mtime;
+ tb[1] = buf.st_mtime;
+ utime(abfd->filename, tb); /* FIXME check result */
+#else
+ struct timeval tv[2];
+ tv[0].tv_sec = buf.st_mtime;
+ tv[0].tv_usec = 0;
+ tv[1].tv_sec = buf.st_mtime;
+ tv[1].tv_usec = 0;
+ utimes(abfd->filename, tv); /* FIXME check result */
+#endif
+ }
+}
+
+
+/* Just do it quickly; don't worry about dups, armap, or anything like that */
+
+/* This is ugly! XXX */
+
+PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (char *filename));
+
+void
+do_quick_append(archive_filename, files_to_append)
+ char *archive_filename;
+ char **files_to_append;
+
+{
+ FILE *ofile,
+ *ifile;
+ char buf[BUFSIZE];
+ long tocopy,
+ thistime;
+ bfd *temp;
+ struct stat sbuf;
+ boolean newfile = false;
+ bfd_error = no_error;
+
+ if (stat(archive_filename, &sbuf) != 0) {
+ if (errno != ENOENT)
+ bfd_fatal(archive_filename);
+ newfile = true;
+ }
+
+
+ ofile = fopen(archive_filename, "a+");
+ if (ofile == NULL) {
+ perror(program_name);
+ exit(1);
+ }
+
+ /* bletch */
+ temp = bfd_openr(archive_filename, NULL);
+ if (temp == NULL) {
+ bfd_perror(archive_filename);
+ exit(1);
+ }
+ if (newfile == false) {
+ if (bfd_check_format(temp, bfd_archive) != true)
+ fatal("File %s is not an archive.", archive_filename);
+ }
+ else {
+ fwrite(ARMAG, 1, SARMAG, ofile);
+ if (!silent_create)
+ fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
+ }
+
+ /* assume it's an achive, go straight to the end, sans $200 */
+ fseek(ofile, 0, 2);
+
+ for (; files_to_append && *files_to_append; ++files_to_append) {
+ struct ar_hdr *hdr = bfd_special_undocumented_glue(*files_to_append);
+ if (hdr == NULL) {
+ bfd_perror(*files_to_append);
+ exit(1);
+ }
+
+ BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
+
+ ifile = fopen(*files_to_append, "r");
+ if (ifile == NULL)
+ bfd_perror(program_name);
+
+ if (stat(*files_to_append, &sbuf) != 0)
+ bfd_perror(*files_to_append);
+
+ tocopy = sbuf.st_size;
+
+ /* XXX should do error-checking! */
+ fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
+
+
+ while (tocopy > 0) {
+ thistime = tocopy;
+ if (thistime > BUFSIZE)
+ thistime = BUFSIZE;
+ fread(buf, 1, thistime, ifile);
+ fwrite(buf, 1, thistime, ofile);
+ tocopy -= thistime;
+ }
+ fclose(ifile);
+ if ((sbuf.st_size % 2) == 1)
+ putc('\n', ofile);
+ }
+ fclose(ofile);
+ bfd_close(temp);
+}
+
+
+void
+write_archive()
+{
+ bfd *obfd;
+ char *xmalloc();
+ int namelen = strlen(inarch->filename);
+ char *new_name = xmalloc(namelen + 6);
+ bfd *contents_head = inarch->next;
+ if (inarch == &bogus_archive) {
+ /* How can this be ? */
+ return;
+ }
+ else {
+
+ strcpy(new_name, inarch->filename);
+ strcpy(new_name + namelen, ".art");
+ obfd = bfd_openw(new_name, bfd_get_target(inarch));
+
+ if (obfd == NULL)
+ bfd_fatal(inarch->filename);
+
+ bfd_set_format(obfd, bfd_archive);
+ obfd->has_armap = write_armap;
+
+ if (bfd_set_archive_head(obfd, contents_head) != true)
+ bfd_fatal(inarch->filename);
+
+ if (!bfd_close(obfd))
+ bfd_fatal(inarch->filename);
+ if (rename(new_name, inarch->filename) != 0)
+ bfd_fatal(inarch->filename);
+ }
+}
+
+
+
+/*
+ returns a pointer to the pointer to the entry which should be rplacd'd
+ into when altering. default_pos should be how to interpret pos_default,
+ and should be a pos value.
+*/
+
+bfd **
+get_pos_bfd(contents, default_pos)
+ bfd **contents;
+ enum pos default_pos;
+{
+ bfd **after_bfd;
+
+ enum pos realpos = (postype == pos_default ? default_pos : postype);
+ switch (realpos) {
+
+ case pos_end:
+ after_bfd = contents;
+ while (*after_bfd) {
+ after_bfd = &((*after_bfd)->next);
+ }
+
+ break;
+#if 0
+ case pos_after:
+ for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
+ if (!strcpy(after_bfd->filename, posname))
+ break;
+ break;
+ case pos_before:
+ for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
+ if (after_bfd->next && (!strcpy(after_bfd->next->filename, posname)))
+ break;
+#endif
+ }
+
+ return after_bfd;
+}
+
+
+void
+delete_members(files_to_delete)
+ char **files_to_delete;
+{
+ bfd **current_ptr_ptr;
+ boolean found;
+ boolean something_changed = false;
+ for (; *files_to_delete != NULL; ++files_to_delete) {
+ /*
+ In a.out systems, the armap is optional. It's also called
+ __.SYMDEF. So if the user asked to delete it, we should remember
+ that fact. The name is NULL in COFF archives, so using this as a
+ key is as good as anything I suppose
+ */
+ if (!strcmp(*files_to_delete, "__.SYMDEF")) {
+ inarch->has_armap = false;
+ write_armap = false;
+ continue;
+ }
+
+ found = false;
+ current_ptr_ptr = &(inarch->next);
+ while (*current_ptr_ptr) {
+ if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
+ found = true;
+ something_changed = true;
+ if (verbose)
+ printf("d - %s\n",
+ *files_to_delete);
+ *current_ptr_ptr = ((*current_ptr_ptr)->next);
+ goto next_file;
+
+ }
+ else {
+ current_ptr_ptr = &((*current_ptr_ptr)->next);
+ }
+ }
+
+ if (verbose && found == false) {
+ printf("No member named `%s'\n", *files_to_delete);
+ }
+next_file:;
+
+ }
+
+ if (something_changed == true) {
+ write_archive();
+ }
+}
+
+
+/* Reposition existing members within an archive */
+
+void
+move_members(files_to_move)
+ char **files_to_move;
+{
+ bfd **after_bfd; /* New entries go after this one */
+ bfd **current_ptr_ptr; /* cdr pointer into contents */
+
+
+
+
+ for (; *files_to_move; ++files_to_move) {
+ current_ptr_ptr = &(inarch->next);
+ while (*current_ptr_ptr) {
+ bfd *current_ptr = *current_ptr_ptr;
+ if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
+ /*
+ Move this file to the end of the list - first cut from
+ where it is.
+ */
+ *current_ptr_ptr = current_ptr->next;
+
+ /* Now glue to end */
+ after_bfd = get_pos_bfd(&inarch->next, pos_end);
+ *after_bfd = current_ptr;
+ current_ptr->next = (bfd *) NULL;
+
+ if (verbose)
+ printf("m - %s\n", *files_to_move);
+
+ goto next_file;
+ }
+ current_ptr_ptr = &((*current_ptr_ptr)->next);
+ }
+ fprintf(stderr, "No entry %s in archive %s!\n",
+ *files_to_move, inarch->filename);
+ exit(1);
+next_file:;
+ }
+
+ write_archive();
+}
+
+
+/* Ought to default to replacing in place, but this is existing practice! */
+
+void
+replace_members(files_to_move)
+ char **files_to_move;
+{
+ bfd **after_bfd; /* New entries go after this one */
+ bfd *current;
+ bfd **current_ptr;
+ bfd *temp;
+ /*
+ If the first item in the archive is an __.SYMDEF then remove it
+ */
+ if (inarch->next &&
+ strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
+ inarch->next = inarch->next->next;
+ }
+
+
+
+ while (files_to_move && *files_to_move) {
+ current_ptr = &inarch->next;
+ while (*current_ptr) {
+ current = *current_ptr;
+
+ if (!strcmp(normalize(*files_to_move), current->filename)) {
+ /* snip out this entry from the chain */
+ *current_ptr = current->next;
+ if (newer_only) {
+ struct stat fsbuf,
+ asbuf;
+ if (stat(*files_to_move, &fsbuf) != 0) {
+ if (errno != ENOENT)
+ bfd_fatal(*files_to_move);
+ goto next_file;
+ }
+ if (bfd_stat_arch_elt(current, &asbuf) != 0)
+ fatal("Internal stat error on %s", current->filename);
+
+ if (fsbuf.st_mtime <= asbuf.st_mtime)
+ goto next_file;
+ }
+
+
+ after_bfd = get_pos_bfd(&inarch->next, pos_end);
+ temp = *after_bfd;
+ *after_bfd = bfd_openr(*files_to_move, NULL);
+ if (*after_bfd == (bfd *) NULL) {
+ fprintf(stderr, "Can't open file %s\n", *files_to_move);
+ exit(1);
+ }
+ (*after_bfd)->next = temp;
+
+ if (verbose) {
+ printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
+ *files_to_move);
+ }
+ goto next_file;
+ }
+ current_ptr = &(current->next);
+ }
+
+ /* It isn't in there, so add to end */
+
+ after_bfd = get_pos_bfd(&inarch->next, pos_end);
+ temp = *after_bfd;
+ *after_bfd = bfd_openr(*files_to_move, NULL);
+ if (*after_bfd == (bfd *) NULL) {
+ fprintf(stderr, "Can't open file %s\n", *files_to_move);
+ exit(1);
+ }
+ if (verbose) {
+ printf("c - %s\n", *files_to_move);
+ }
+
+ (*after_bfd)->next = temp;
+
+next_file:;
+
+ files_to_move++;
+ }
+
+
+ write_archive();
+}
+
+void
+ranlib_only(archname)
+ char *archname;
+{
+ write_armap = true;
+ open_inarch(archname);
+ write_archive();
+ exit(0);
+}
diff --git a/binutils/bucomm.c b/binutils/bucomm.c
new file mode 100644
index 0000000..00f379f
--- /dev/null
+++ b/binutils/bucomm.c
@@ -0,0 +1,151 @@
+/*** bucomm.c -- Bin Utils COMmon code.
+
+ We might put this in a library someday so it could be dynamically
+ loaded, but for now it's not necessary */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include <varargs.h>
+
+char *target = NULL; /* default as late as possible */
+
+/* Yes, this is what atexit is for, but that isn't guaranteed yet.
+ And yes, I know this isn't as good, but it does what is needed just fine */
+void (*exit_handler) ();
+
+/** Memory hackery */
+
+PROTO (char *, malloc, (unsigned size));
+PROTO (char *, realloc, (char *ptr, unsigned size));
+
+
+/* Error reporting */
+
+char *program_name;
+
+void
+bfd_fatal (string)
+ char *string;
+{
+ char *errmsg = bfd_errmsg (bfd_error);
+
+ if (string)
+ fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
+ else
+ fprintf (stderr, "%s: %s\n", program_name, errmsg);
+
+ if (NULL != exit_handler) (*exit_handler) ();
+ exit (1);
+}
+
+#ifndef NO_STDARG
+void
+fatal (Format)
+ const char *Format;
+{
+ va_list args;
+
+ va_start (args, Format);
+ vfprintf (stderr, Format, args);
+ va_end (args);
+ (void) putc ('\n', stderr);
+ if (NULL != exit_handler) (*exit_handler) ();
+ exit (1);
+}
+#else
+#ifndef NO_VARARGS
+void fatal (va_alist)
+ va_dcl
+{
+ char *Format;
+ va_list args;
+
+ va_start (args);
+ Format = va_arg(args, char *);
+ vfprintf (stderr, Format, args);
+ va_end (args);
+ (void) putc ('\n', stderr);
+ if (NULL != exit_handler) (*exit_handler) ();
+ exit (1);
+} /* fatal() */
+#else
+/*VARARGS1 */
+fatal (Format, args)
+ char *Format;
+{
+ as_where ();
+ _doprnt (Format, &args, stderr); /* not terribly portable, but... */
+ (void) putc ('\n', stderr);
+ if (NULL != exit_handler) (*exit_handler) ();
+ exit (1);
+}
+#endif /* not NO_VARARGS */
+#endif /* not NO_STDARG */
+
+
+/** Display the archive header for an element as if it were an ls -l listing */
+
+/* Mode User\tGroup\tSize\tDate Name */
+
+void
+print_arelt_descr (abfd, verbose)
+ bfd *abfd;
+ boolean verbose;
+{
+ struct stat buf;
+ char modebuf[11];
+ char timebuf[40];
+ long when;
+ long current_time = time ((long *) 0);
+
+ if (verbose) {
+
+ if (bfd_stat_arch_elt (abfd, &buf) == 0) { /* if not, huh? */
+
+ mode_string (buf.st_mode, modebuf);
+ modebuf[10] = '\0';
+ fputs (modebuf, stdout);
+
+ when = buf.st_mtime;
+ strcpy (timebuf, ctime (&when));
+
+ /* This code comes from gnu ls. */
+ if ((current_time - when > 6 * 30 * 24 * 60 * 60)
+ || (current_time - when < 0)) {
+ /* The file is fairly old or in the future.
+ POSIX says the cutoff is 6 months old;
+ approximate this by 6*30 days.
+ Show the year instead of the time of day. */
+ strcpy (timebuf + 11, timebuf + 19);
+ }
+ timebuf[16] = 0;
+
+ printf (" %d\t%d\t%ld\t%s ", buf.st_uid, buf.st_gid, buf.st_size, timebuf);
+ }
+ }
+
+ puts (abfd->filename);
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *result = malloc (size);
+ if (result == NULL && size != NULL) fatal ("virtual memory exhausted");
+
+ return result;
+}
+
+/* Like realloc but get fatal error if memory is exhausted. */
+char *
+xrealloc (ptr, size)
+ char *ptr;
+ unsigned size;
+{
+ register char *result = realloc (ptr, size);
+ if (result == 0 && size != 0) fatal ("virtual memory exhausted");
+
+ return result;
+}
diff --git a/binutils/filemode.c b/binutils/filemode.c
new file mode 100644
index 0000000..1bb5e64
--- /dev/null
+++ b/binutils/filemode.c
@@ -0,0 +1,193 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+void
+filemodestring (statp, str)
+ struct stat *statp;
+ char *str;
+{
+ mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+ is given as an argument. */
+
+void
+mode_string (mode, str)
+ unsigned short mode;
+ char *str;
+{
+ str[0] = ftypelet (mode);
+ rwx ((mode & 0700) << 0, &str[1]);
+ rwx ((mode & 0070) << 3, &str[4]);
+ rwx ((mode & 0007) << 6, &str[7]);
+ setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for any other file type. */
+
+static char
+ftypelet (bits)
+ unsigned short bits;
+{
+ switch (bits & S_IFMT)
+ {
+ default:
+ return '-';
+ case S_IFDIR:
+ return 'd';
+#ifdef S_IFLNK
+ case S_IFLNK:
+ return 'l';
+#endif
+#ifdef S_IFCHR
+ case S_IFCHR:
+ return 'c';
+#endif
+#ifdef S_IFBLK
+ case S_IFBLK:
+ return 'b';
+#endif
+#ifdef S_IFMPC
+ case S_IFMPC:
+ case S_IFMPB:
+ return 'm';
+#endif
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ return 's';
+#endif
+#ifdef S_IFIFO
+#if S_IFIFO != S_IFSOCK
+ case S_IFIFO:
+ return 'p';
+#endif
+#endif
+#ifdef S_IFNWK /* HP-UX */
+ case S_IFNWK:
+ return 'n';
+#endif
+ }
+}
+
+/* Look at read, write, and execute bits in BITS and set
+ flags in CHARS accordingly. */
+
+static void
+rwx (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+ chars[0] = (bits & S_IREAD) ? 'r' : '-';
+ chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+ chars[2] = (bits & S_IEXEC) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
+
+
diff --git a/binutils/i960-pinsn.c b/binutils/i960-pinsn.c
new file mode 100644
index 0000000..1c7b719
--- /dev/null
+++ b/binutils/i960-pinsn.c
@@ -0,0 +1,820 @@
+/* Disassemble i80960 instructions.
+ */
+
+/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Diddler.
+
+BFD is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+BFD is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BFD; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$
+ $Log
+*/
+#include <stdio.h>
+#include "sysdep.h"
+#include "bfd.h"
+
+extern char *xmalloc();
+extern int fputs();
+
+static char *reg_names[] = {
+/* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7",
+/* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+/* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
+/* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp",
+/* 32 */ "pc", "ac", "ip", "tc", "fp0", "fp1", "fp2", "fp3"
+};
+
+
+static FILE *stream; /* Output goes here */
+static void print_addr();
+static void ctrl();
+static void cobr();
+static void reg();
+static int mem();
+static void ea();
+static void dstop();
+static void regop();
+static void invalid();
+static int pinsn();
+static void put_abs();
+
+
+/* Print the i960 instruction at address 'memaddr' in debugged memory,
+ * on stream 's'. Returns length of the instruction, in bytes.
+ */
+int
+print_insn_i960( memaddr, buffer, s )
+ bfd_vma memaddr;
+uint8e_type *buffer;
+ FILE *s;
+{
+ unsigned int word1, word2;
+
+ stream = s;
+ word1 =buffer [0] |( buffer[1]<< 8) | (buffer[2] << 16) | ( buffer[3] <<24);
+ word2 =buffer [4] |( buffer[5]<< 8) | (buffer[6] << 16) | ( buffer[7] <<24);
+ return pinsn( memaddr, word1, word2 );
+}
+
+#define IN_GDB
+
+/*****************************************************************************
+ * All code below this point should be identical with that of
+ * the disassembler in gdmp960.
+ *****************************************************************************/
+
+struct tabent {
+ char *name;
+ char numops;
+};
+
+static int
+pinsn( memaddr, word1, word2 )
+ unsigned long memaddr;
+ unsigned long word1, word2;
+{
+ int instr_len;
+
+ instr_len = 4;
+ put_abs( word1, word2 );
+
+ /* Divide instruction set into classes based on high 4 bits of opcode*/
+ switch ( (word1 >> 28) & 0xf ){
+ case 0x0:
+ case 0x1:
+ ctrl( memaddr, word1, word2 );
+ break;
+ case 0x2:
+ case 0x3:
+ cobr( memaddr, word1, word2 );
+ break;
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ reg( word1 );
+ break;
+ case 0x8:
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ instr_len = mem( memaddr, word1, word2, 0 );
+ break;
+ default:
+ /* invalid instruction, print as data word */
+ invalid( word1 );
+ break;
+ }
+ return instr_len;
+}
+
+/****************************************/
+/* CTRL format */
+/****************************************/
+static void
+ctrl( memaddr, word1, word2 )
+ unsigned long memaddr;
+ unsigned long word1, word2;
+{
+ int i;
+ static struct tabent ctrl_tab[] = {
+ NULL, 0, /* 0x00 */
+ NULL, 0, /* 0x01 */
+ NULL, 0, /* 0x02 */
+ NULL, 0, /* 0x03 */
+ NULL, 0, /* 0x04 */
+ NULL, 0, /* 0x05 */
+ NULL, 0, /* 0x06 */
+ NULL, 0, /* 0x07 */
+ "b", 1, /* 0x08 */
+ "call", 1, /* 0x09 */
+ "ret", 0, /* 0x0a */
+ "bal", 1, /* 0x0b */
+ NULL, 0, /* 0x0c */
+ NULL, 0, /* 0x0d */
+ NULL, 0, /* 0x0e */
+ NULL, 0, /* 0x0f */
+ "bno", 1, /* 0x10 */
+ "bg", 1, /* 0x11 */
+ "be", 1, /* 0x12 */
+ "bge", 1, /* 0x13 */
+ "bl", 1, /* 0x14 */
+ "bne", 1, /* 0x15 */
+ "ble", 1, /* 0x16 */
+ "bo", 1, /* 0x17 */
+ "faultno", 0, /* 0x18 */
+ "faultg", 0, /* 0x19 */
+ "faulte", 0, /* 0x1a */
+ "faultge", 0, /* 0x1b */
+ "faultl", 0, /* 0x1c */
+ "faultne", 0, /* 0x1d */
+ "faultle", 0, /* 0x1e */
+ "faulto", 0, /* 0x1f */
+ };
+
+ i = (word1 >> 24) & 0xff;
+ if ( (ctrl_tab[i].name == NULL) || ((word1 & 1) != 0) ){
+ invalid( word1 );
+ return;
+ }
+
+ fputs( ctrl_tab[i].name, stream );
+ if ( word1 & 2 ){ /* Predicts branch not taken */
+ fputs( ".f", stream );
+ }
+
+ if ( ctrl_tab[i].numops == 1 ){
+ /* EXTRACT DISPLACEMENT AND CONVERT TO ADDRESS */
+ word1 &= 0x00ffffff;
+ if ( word1 & 0x00800000 ){ /* Sign bit is set */
+ word1 |= (-1 & ~0xffffff); /* Sign extend */
+ }
+ putc( '\t', stream );
+ print_addr( word1 + memaddr );
+ }
+}
+
+/****************************************/
+/* COBR format */
+/****************************************/
+static void
+cobr( memaddr, word1, word2 )
+ unsigned long memaddr;
+ unsigned long word1, word2;
+{
+ int src1;
+ int src2;
+ int i;
+
+ static struct tabent cobr_tab[] = {
+ "testno", 1, /* 0x20 */
+ "testg", 1, /* 0x21 */
+ "teste", 1, /* 0x22 */
+ "testge", 1, /* 0x23 */
+ "testl", 1, /* 0x24 */
+ "testne", 1, /* 0x25 */
+ "testle", 1, /* 0x26 */
+ "testo", 1, /* 0x27 */
+ NULL, 0, /* 0x28 */
+ NULL, 0, /* 0x29 */
+ NULL, 0, /* 0x2a */
+ NULL, 0, /* 0x2b */
+ NULL, 0, /* 0x2c */
+ NULL, 0, /* 0x2d */
+ NULL, 0, /* 0x2e */
+ NULL, 0, /* 0x2f */
+ "bbc", 3, /* 0x30 */
+ "cmpobg", 3, /* 0x31 */
+ "cmpobe", 3, /* 0x32 */
+ "cmpobge", 3, /* 0x33 */
+ "cmpobl", 3, /* 0x34 */
+ "cmpobne", 3, /* 0x35 */
+ "cmpoble", 3, /* 0x36 */
+ "bbs", 3, /* 0x37 */
+ "cmpibno", 3, /* 0x38 */
+ "cmpibg", 3, /* 0x39 */
+ "cmpibe", 3, /* 0x3a */
+ "cmpibge", 3, /* 0x3b */
+ "cmpibl", 3, /* 0x3c */
+ "cmpibne", 3, /* 0x3d */
+ "cmpible", 3, /* 0x3e */
+ "cmpibo", 3, /* 0x3f */
+ };
+
+ i = ((word1 >> 24) & 0xff) - 0x20;
+ if ( cobr_tab[i].name == NULL ){
+ invalid( word1 );
+ return;
+ }
+
+ fputs( cobr_tab[i].name, stream );
+ if ( word1 & 2 ){ /* Predicts branch not taken */
+ fputs( ".f", stream );
+ }
+ putc( '\t', stream );
+
+ src1 = (word1 >> 19) & 0x1f;
+ src2 = (word1 >> 14) & 0x1f;
+
+ if ( word1 & 0x02000 ){ /* M1 is 1 */
+ fprintf( stream, "%d", src1 );
+ } else { /* M1 is 0 */
+ fputs( reg_names[src1], stream );
+ }
+
+ if ( cobr_tab[i].numops > 1 ){
+ if ( word1 & 1 ){ /* S2 is 1 */
+ fprintf( stream, ",sf%d,", src2 );
+ } else { /* S1 is 0 */
+ fprintf( stream, ",%s,", reg_names[src2] );
+ }
+
+ /* Extract displacement and convert to address
+ */
+ word1 &= 0x00001ffc;
+ if ( word1 & 0x00001000 ){ /* Negative displacement */
+ word1 |= (-1 & ~0x1fff); /* Sign extend */
+ }
+ print_addr( memaddr + word1 );
+ }
+}
+
+/****************************************/
+/* MEM format */
+/****************************************/
+static int /* returns instruction length: 4 or 8 */
+mem( memaddr, word1, word2, noprint )
+ unsigned long memaddr;
+ unsigned long word1, word2;
+ int noprint; /* If TRUE, return instruction length, but
+ * don't output any text.
+ */
+{
+ int i, j;
+ int len;
+ int mode;
+ int offset;
+ char *reg1, *reg2, *reg3;
+
+ /* This lookup table is too sparse to make it worth typing in, but not
+ * so large as to make a sparse array necessary. We allocate the
+ * table at runtime, initialize all entries to empty, and copy the
+ * real ones in from an initialization table.
+ *
+ * NOTE: In this table, the meaning of 'numops' is:
+ * 1: single operand
+ * 2: 2 operands, load instruction
+ * -2: 2 operands, store instruction
+ */
+ static struct tabent *mem_tab = NULL;
+ static struct { int opcode; char *name; char numops; } mem_init[] = {
+#define MEM_MIN 0x80
+ 0x80, "ldob", 2,
+ 0x82, "stob", -2,
+ 0x84, "bx", 1,
+ 0x85, "balx", 2,
+ 0x86, "callx", 1,
+ 0x88, "ldos", 2,
+ 0x8a, "stos", -2,
+ 0x8c, "lda", 2,
+ 0x90, "ld", 2,
+ 0x92, "st", -2,
+ 0x98, "ldl", 2,
+ 0x9a, "stl", -2,
+ 0xa0, "ldt", 2,
+ 0xa2, "stt", -2,
+ 0xb0, "ldq", 2,
+ 0xb2, "stq", -2,
+ 0xc0, "ldib", 2,
+ 0xc2, "stib", -2,
+ 0xc8, "ldis", 2,
+ 0xca, "stis", -2,
+#define MEM_MAX 0xca
+#define MEM_SIZ ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent))
+ 0, NULL, 0
+ };
+
+ if ( mem_tab == NULL ){
+ mem_tab = (struct tabent *) xmalloc( MEM_SIZ );
+ bzero( (void *) mem_tab, MEM_SIZ );
+ for ( i = 0; mem_init[i].opcode != 0; i++ ){
+ j = mem_init[i].opcode - MEM_MIN;
+ mem_tab[j].name = mem_init[i].name;
+ mem_tab[j].numops = mem_init[i].numops;
+ }
+ }
+
+ i = ((word1 >> 24) & 0xff) - MEM_MIN;
+ mode = (word1 >> 10) & 0xf;
+
+ if ( (mem_tab[i].name != NULL) /* Valid instruction */
+ && ((mode == 5) || (mode >=12)) ){ /* With 32-bit displacement */
+ len = 8;
+ } else {
+ len = 4;
+ }
+
+ if ( noprint ){
+ return len;
+ }
+
+ if ( (mem_tab[i].name == NULL) || (mode == 6) ){
+ invalid( word1 );
+ return len;
+ }
+
+ fprintf( stream, "%s\t", mem_tab[i].name );
+
+ reg1 = reg_names[ (word1 >> 19) & 0x1f ]; /* MEMB only */
+ reg2 = reg_names[ (word1 >> 14) & 0x1f ];
+ reg3 = reg_names[ word1 & 0x1f ]; /* MEMB only */
+ offset = word1 & 0xfff; /* MEMA only */
+
+ switch ( mem_tab[i].numops ){
+
+ case 2: /* LOAD INSTRUCTION */
+ if ( mode & 4 ){ /* MEMB FORMAT */
+ ea( memaddr, mode, reg2, reg3, word1, word2 );
+ fprintf( stream, ",%s", reg1 );
+ } else { /* MEMA FORMAT */
+ fprintf( stream, "0x%x", (unsigned) offset );
+ if (mode & 8) {
+ fprintf( stream, "(%s)", reg2 );
+ }
+ fprintf( stream, ",%s", reg1 );
+ }
+ break;
+
+ case -2: /* STORE INSTRUCTION */
+ if ( mode & 4 ){ /* MEMB FORMAT */
+ fprintf( stream, "%s,", reg1 );
+ ea( memaddr, mode, reg2, reg3, word1, word2 );
+ } else { /* MEMA FORMAT */
+ fprintf( stream, "%s,0x%x", reg1, (unsigned) offset );
+ if (mode & 8) {
+ fprintf( stream, "(%s)", reg2 );
+ }
+ }
+ break;
+
+ case 1: /* BX/CALLX INSTRUCTION */
+ if ( mode & 4 ){ /* MEMB FORMAT */
+ ea( memaddr, mode, reg2, reg3, word1, word2 );
+ } else { /* MEMA FORMAT */
+ fprintf( stream, "0x%x", (unsigned) offset );
+ if (mode & 8) {
+ fprintf( stream, "(%s)", reg2 );
+ }
+ }
+ break;
+ }
+
+ return len;
+}
+
+/****************************************/
+/* REG format */
+/****************************************/
+static void
+reg( word1 )
+ unsigned long word1;
+{
+ int i, j;
+ int opcode;
+ int fp;
+ int m1, m2, m3;
+ int s1, s2;
+ int src, src2, dst;
+ char *mnemp;
+
+ /* This lookup table is too sparse to make it worth typing in, but not
+ * so large as to make a sparse array necessary. We allocate the
+ * table at runtime, initialize all entries to empty, and copy the
+ * real ones in from an initialization table.
+ *
+ * NOTE: In this table, the meaning of 'numops' is:
+ * 1: single operand, which is NOT a destination.
+ * -1: single operand, which IS a destination.
+ * 2: 2 operands, the 2nd of which is NOT a destination.
+ * -2: 2 operands, the 2nd of which IS a destination.
+ * 3: 3 operands
+ *
+ * If an opcode mnemonic begins with "F", it is a floating-point
+ * opcode (the "F" is not printed).
+ */
+
+ static struct tabent *reg_tab = NULL;
+ static struct { int opcode; char *name; char numops; } reg_init[] = {
+#define REG_MIN 0x580
+ 0x580, "notbit", 3,
+ 0x581, "and", 3,
+ 0x582, "andnot", 3,
+ 0x583, "setbit", 3,
+ 0x584, "notand", 3,
+ 0x586, "xor", 3,
+ 0x587, "or", 3,
+ 0x588, "nor", 3,
+ 0x589, "xnor", 3,
+ 0x58a, "not", -2,
+ 0x58b, "ornot", 3,
+ 0x58c, "clrbit", 3,
+ 0x58d, "notor", 3,
+ 0x58e, "nand", 3,
+ 0x58f, "alterbit", 3,
+ 0x590, "addo", 3,
+ 0x591, "addi", 3,
+ 0x592, "subo", 3,
+ 0x593, "subi", 3,
+ 0x598, "shro", 3,
+ 0x59a, "shrdi", 3,
+ 0x59b, "shri", 3,
+ 0x59c, "shlo", 3,
+ 0x59d, "rotate", 3,
+ 0x59e, "shli", 3,
+ 0x5a0, "cmpo", 2,
+ 0x5a1, "cmpi", 2,
+ 0x5a2, "concmpo", 2,
+ 0x5a3, "concmpi", 2,
+ 0x5a4, "cmpinco", 3,
+ 0x5a5, "cmpinci", 3,
+ 0x5a6, "cmpdeco", 3,
+ 0x5a7, "cmpdeci", 3,
+ 0x5ac, "scanbyte", 2,
+ 0x5ae, "chkbit", 2,
+ 0x5b0, "addc", 3,
+ 0x5b2, "subc", 3,
+ 0x5cc, "mov", -2,
+ 0x5d8, "eshro", 3,
+ 0x5dc, "movl", -2,
+ 0x5ec, "movt", -2,
+ 0x5fc, "movq", -2,
+ 0x600, "synmov", 2,
+ 0x601, "synmovl", 2,
+ 0x602, "synmovq", 2,
+ 0x603, "cmpstr", 3,
+ 0x604, "movqstr", 3,
+ 0x605, "movstr", 3,
+ 0x610, "atmod", 3,
+ 0x612, "atadd", 3,
+ 0x613, "inspacc", -2,
+ 0x614, "ldphy", -2,
+ 0x615, "synld", -2,
+ 0x617, "fill", 3,
+ 0x630, "sdma", 3,
+ 0x631, "udma", 0,
+ 0x640, "spanbit", -2,
+ 0x641, "scanbit", -2,
+ 0x642, "daddc", 3,
+ 0x643, "dsubc", 3,
+ 0x644, "dmovt", -2,
+ 0x645, "modac", 3,
+ 0x646, "condrec", -2,
+ 0x650, "modify", 3,
+ 0x651, "extract", 3,
+ 0x654, "modtc", 3,
+ 0x655, "modpc", 3,
+ 0x656, "receive", -2,
+ 0x659, "sysctl", 3,
+ 0x660, "calls", 1,
+ 0x662, "send", 3,
+ 0x663, "sendserv", 1,
+ 0x664, "resumprcs", 1,
+ 0x665, "schedprcs", 1,
+ 0x666, "saveprcs", 0,
+ 0x668, "condwait", 1,
+ 0x669, "wait", 1,
+ 0x66a, "signal", 1,
+ 0x66b, "mark", 0,
+ 0x66c, "fmark", 0,
+ 0x66d, "flushreg", 0,
+ 0x66f, "syncf", 0,
+ 0x670, "emul", 3,
+ 0x671, "ediv", 3,
+ 0x673, "ldtime", -1,
+ 0x674, "Fcvtir", -2,
+ 0x675, "Fcvtilr", -2,
+ 0x676, "Fscalerl", 3,
+ 0x677, "Fscaler", 3,
+ 0x680, "Fatanr", 3,
+ 0x681, "Flogepr", 3,
+ 0x682, "Flogr", 3,
+ 0x683, "Fremr", 3,
+ 0x684, "Fcmpor", 2,
+ 0x685, "Fcmpr", 2,
+ 0x688, "Fsqrtr", -2,
+ 0x689, "Fexpr", -2,
+ 0x68a, "Flogbnr", -2,
+ 0x68b, "Froundr", -2,
+ 0x68c, "Fsinr", -2,
+ 0x68d, "Fcosr", -2,
+ 0x68e, "Ftanr", -2,
+ 0x68f, "Fclassr", 1,
+ 0x690, "Fatanrl", 3,
+ 0x691, "Flogeprl", 3,
+ 0x692, "Flogrl", 3,
+ 0x693, "Fremrl", 3,
+ 0x694, "Fcmporl", 2,
+ 0x695, "Fcmprl", 2,
+ 0x698, "Fsqrtrl", -2,
+ 0x699, "Fexprl", -2,
+ 0x69a, "Flogbnrl", -2,
+ 0x69b, "Froundrl", -2,
+ 0x69c, "Fsinrl", -2,
+ 0x69d, "Fcosrl", -2,
+ 0x69e, "Ftanrl", -2,
+ 0x69f, "Fclassrl", 1,
+ 0x6c0, "Fcvtri", -2,
+ 0x6c1, "Fcvtril", -2,
+ 0x6c2, "Fcvtzri", -2,
+ 0x6c3, "Fcvtzril", -2,
+ 0x6c9, "Fmovr", -2,
+ 0x6d9, "Fmovrl", -2,
+ 0x6e1, "Fmovre", -2,
+ 0x6e2, "Fcpysre", 3,
+ 0x6e3, "Fcpyrsre", 3,
+ 0x701, "mulo", 3,
+ 0x708, "remo", 3,
+ 0x70b, "divo", 3,
+ 0x741, "muli", 3,
+ 0x748, "remi", 3,
+ 0x749, "modi", 3,
+ 0x74b, "divi", 3,
+ 0x78b, "Fdivr", 3,
+ 0x78c, "Fmulr", 3,
+ 0x78d, "Fsubr", 3,
+ 0x78f, "Faddr", 3,
+ 0x79b, "Fdivrl", 3,
+ 0x79c, "Fmulrl", 3,
+ 0x79d, "Fsubrl", 3,
+ 0x79f, "Faddrl", 3,
+#define REG_MAX 0x79f
+#define REG_SIZ ((REG_MAX-REG_MIN+1) * sizeof(struct tabent))
+ 0, NULL, 0
+ };
+
+ if ( reg_tab == NULL ){
+ reg_tab = (struct tabent *) xmalloc( REG_SIZ );
+ bzero( (void *) reg_tab, REG_SIZ );
+ for ( i = 0; reg_init[i].opcode != 0; i++ ){
+ j = reg_init[i].opcode - REG_MIN;
+ reg_tab[j].name = reg_init[i].name;
+ reg_tab[j].numops = reg_init[i].numops;
+ }
+ }
+
+ opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf);
+ i = opcode - REG_MIN;
+
+ if ( (opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL) ){
+ invalid( word1 );
+ return;
+ }
+
+ mnemp = reg_tab[i].name;
+ if ( *mnemp == 'F' ){
+ fp = 1;
+ mnemp++;
+ } else {
+ fp = 0;
+ }
+
+ fputs( mnemp, stream );
+
+ s1 = (word1 >> 5) & 1;
+ s2 = (word1 >> 6) & 1;
+ m1 = (word1 >> 11) & 1;
+ m2 = (word1 >> 12) & 1;
+ m3 = (word1 >> 13) & 1;
+ src = word1 & 0x1f;
+ src2 = (word1 >> 14) & 0x1f;
+ dst = (word1 >> 19) & 0x1f;
+
+ if ( reg_tab[i].numops != 0 ){
+ putc( '\t', stream );
+
+ switch ( reg_tab[i].numops ){
+ case 1:
+ regop( m1, s1, src, fp );
+ break;
+ case -1:
+ dstop( m3, dst, fp );
+ break;
+ case 2:
+ regop( m1, s1, src, fp );
+ putc( ',', stream );
+ regop( m2, s2, src2, fp );
+ break;
+ case -2:
+ regop( m1, s1, src, fp );
+ putc( ',', stream );
+ dstop( m3, dst, fp );
+ break;
+ case 3:
+ regop( m1, s1, src, fp );
+ putc( ',', stream );
+ regop( m2, s2, src2, fp );
+ putc( ',', stream );
+ dstop( m3, dst, fp );
+ break;
+ }
+ }
+}
+
+
+/*
+ * Print out effective address for memb instructions.
+ */
+static void
+ea( memaddr, mode, reg2, reg3, word1, word2 )
+ unsigned long memaddr;
+ int mode;
+ char *reg2, *reg3;
+int word1;
+ unsigned int word2;
+{
+ int scale;
+ static int scale_tab[] = { 1, 2, 4, 8, 16 };
+
+ scale = (word1 >> 7) & 0x07;
+ if ( (scale > 4) || ((word1 >> 5) & 0x03 != 0) ){
+ invalid( word1 );
+ return;
+ }
+ scale = scale_tab[scale];
+
+ switch (mode) {
+ case 4: /* (reg) */
+ fprintf( stream, "(%s)", reg2 );
+ break;
+ case 5: /* displ+8(ip) */
+ print_addr( word2+8+memaddr );
+ break;
+ case 7: /* (reg)[index*scale] */
+ if (scale == 1) {
+ fprintf( stream, "(%s)[%s]", reg2, reg3 );
+ } else {
+ fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale);
+ }
+ break;
+ case 12: /* displacement */
+ print_addr( word2 );
+ break;
+ case 13: /* displ(reg) */
+ print_addr( word2 );
+ fprintf( stream, "(%s)", reg2 );
+ break;
+ case 14: /* displ[index*scale] */
+ print_addr( word2 );
+ if (scale == 1) {
+ fprintf( stream, "[%s]", reg3 );
+ } else {
+ fprintf( stream, "[%s*%d]", reg3, scale );
+ }
+ break;
+ case 15: /* displ(reg)[index*scale] */
+ print_addr( word2 );
+ if (scale == 1) {
+ fprintf( stream, "(%s)[%s]", reg2, reg3 );
+ } else {
+ fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale );
+ }
+ break;
+ default:
+ invalid( word1 );
+ return;
+ }
+}
+
+
+/************************************************/
+/* Register Instruction Operand */
+/************************************************/
+static void
+regop( mode, spec, reg, fp )
+ int mode, spec, reg, fp;
+{
+ if ( fp ){ /* FLOATING POINT INSTRUCTION */
+ if ( mode == 1 ){ /* FP operand */
+ switch ( reg ){
+ case 0: fputs( "fp0", stream ); break;
+ case 1: fputs( "fp1", stream ); break;
+ case 2: fputs( "fp2", stream ); break;
+ case 3: fputs( "fp3", stream ); break;
+ case 16: fputs( "0f0.0", stream ); break;
+ case 22: fputs( "0f1.0", stream ); break;
+ default: putc( '?', stream ); break;
+ }
+ } else { /* Non-FP register */
+ fputs( reg_names[reg], stream );
+ }
+ } else { /* NOT FLOATING POINT */
+ if ( mode == 1 ){ /* Literal */
+ fprintf( stream, "%d", reg );
+ } else { /* Register */
+ if ( spec == 0 ){
+ fputs( reg_names[reg], stream );
+ } else {
+ fprintf( stream, "sf%d", reg );
+ }
+ }
+ }
+}
+
+/************************************************/
+/* Register Instruction Destination Operand */
+/************************************************/
+static void
+dstop( mode, reg, fp )
+ int mode, reg, fp;
+{
+ /* 'dst' operand can't be a literal. On non-FP instructions, register
+ * mode is assumed and "m3" acts as if were "s3"; on FP-instructions,
+ * sf registers are not allowed so m3 acts normally.
+ */
+ if ( fp ){
+ regop( mode, 0, reg, fp );
+ } else {
+ regop( 0, mode, reg, fp );
+ }
+}
+
+
+static void
+invalid( word1 )
+ int word1;
+{
+ fprintf( stream, ".word\t0x%08x", (unsigned) word1 );
+}
+
+static void
+print_addr(a)
+int a;
+{
+ fprintf( stream, "0x%x", (unsigned) a );
+}
+
+static void
+put_abs( word1, word2 )
+ unsigned long word1, word2;
+{
+#ifdef IN_GDB
+ return;
+#else
+ int len;
+
+ switch ( (word1 >> 28) & 0xf ){
+ case 0x8:
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ /* MEM format instruction */
+ len = mem( 0, word1, word2, 1 );
+ break;
+ default:
+ len = 4;
+ break;
+ }
+
+ if ( len == 8 ){
+ fprintf( stream, "%08x %08x\t", word1, word2 );
+ } else {
+ fprintf( stream, "%08x \t", word1 );
+ }
+;
+
+#endif
+}
diff --git a/binutils/m68k-pinsn.c b/binutils/m68k-pinsn.c
new file mode 100644
index 0000000..284f335
--- /dev/null
+++ b/binutils/m68k-pinsn.c
@@ -0,0 +1,806 @@
+/* Print m68k instructions for objdump
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+
+This file is part of the binutils.
+
+The binutils are free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The binutils are distributed in the hope that they will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the binutils; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$
+ $Log$
+ Revision 1.1 1991/03/21 21:26:45 gumby
+ Initial revision
+
+ * Revision 1.1 1991/03/13 00:34:06 chrisb
+ * Initial revision
+ *
+ * Revision 1.4 1991/03/09 04:36:34 rich
+ * Modified Files:
+ * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
+ * binutils.h
+ *
+ * Pulled sysdep.h out of bfd.h.
+ *
+ * Revision 1.3 1991/03/08 21:54:45 rich
+ * Modified Files:
+ * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
+ * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
+ * sparc-pinsn.c strip.c
+ *
+ * Verifying Portland tree with steve's last changes. Also, some partial
+ * porting.
+ *
+ * Revision 1.2 1991/03/08 07:46:24 sac
+ * Added -l option to disassembly - prints line numbers too.
+ *
+ * Revision 1.1 1991/02/22 16:48:02 sac
+ * Initial revision
+ *
+*/
+
+#include <stdio.h>
+#include "sysdep.h"
+#include "bfd.h"
+#include "m68k-opcode.h"
+
+extern int fputs();
+extern void print_address();
+
+/* 68k instructions are never longer than this many bytes. */
+#define MAXLEN 22
+
+/* Number of elements in the opcode table. */
+#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
+
+extern char *reg_names[];
+char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
+ "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
+
+char *reg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"};
+static unsigned char *print_insn_arg ();
+static unsigned char *print_indexed ();
+static void print_base ();
+static int fetch_arg ();
+
+#define NEXTBYTE(p) (p += 2, ((char *)p)[-1])
+
+#define NEXTWORD(p) \
+ (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
+
+#define NEXTLONG(p) \
+ (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
+
+#define NEXTSINGLE(p) \
+ (p += 4, *((float *)(p - 4)))
+
+#define NEXTDOUBLE(p) \
+ (p += 8, *((double *)(p - 8)))
+
+#define NEXTEXTEND(p) \
+ (p += 12, 0.0) /* Need a function to convert from extended to double
+ precision... */
+
+#define NEXTPACKED(p) \
+ (p += 12, 0.0) /* Need a function to convert from packed to double
+ precision. Actually, it's easier to print a
+ packed number than a double anyway, so maybe
+ there should be a special case to handle this... */
+
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+ on STREAM. Returns length of the instruction, in bytes. */
+
+int
+print_insn_m68k(addr, buffer, stream)
+ bfd_vma addr;
+unsigned char *buffer;
+ FILE *stream;
+{
+ register unsigned int i;
+ register unsigned char *p;
+ register char *d;
+ register unsigned int bestmask;
+ int best;
+
+
+
+ bestmask = 0;
+ best = -1;
+ for (i = 0; i < NOPCODES; i++)
+ {
+ register unsigned int opcode = m68k_opcodes[i].opcode;
+ register unsigned int match = m68k_opcodes[i].match;
+ if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
+ && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
+ && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+ && ((0xff & buffer[3] & match) == (0xff & opcode)))
+ {
+ /* Don't use for printout the variants of divul and divsl
+ that have the same register number in two places.
+ The more general variants will match instead. */
+ for (d = m68k_opcodes[i].args; *d; d += 2)
+ if (d[1] == 'D')
+ break;
+
+ /* Don't use for printout the variants of most floating
+ point coprocessor instructions which use the same
+ register number in two places, as above. */
+ if (*d == 0)
+ for (d = m68k_opcodes[i].args; *d; d += 2)
+ if (d[1] == 't')
+ break;
+
+ if (*d == 0 && match > bestmask)
+ {
+ best = i;
+ bestmask = match;
+ }
+ }
+ }
+
+ /* Handle undefined instructions. */
+ if (best < 0)
+ {
+ fprintf (stream, "0%o", (unsigned) (buffer[0] << 8) + buffer[1]);
+ return 2;
+ }
+
+ fprintf (stream, "%s", m68k_opcodes[best].name);
+
+ /* Point at first word of argument data,
+ and at descriptor for first argument. */
+ p = buffer + 2;
+
+ /* Why do this this way? -MelloN */
+ for (d = m68k_opcodes[best].args; *d; d += 2)
+ {
+ if (d[0] == '#')
+ {
+ if (d[1] == 'l' && p - buffer < 6)
+ p = buffer + 6;
+ else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
+ p = buffer + 4;
+ }
+ if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
+ p = buffer + 4;
+ if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
+ p = buffer + 6;
+ if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
+ p = buffer + 4;
+ }
+
+ d = m68k_opcodes[best].args;
+
+ if (*d)
+ fputs (" ", stream);
+
+ while (*d)
+ {
+ p = print_insn_arg (d, buffer, p, addr + p - buffer, stream);
+ d += 2;
+ if (*d && *(d - 2) != 'I' && *d != 'k')
+ fputs (",", stream);
+ }
+ return p - buffer;
+}
+
+static unsigned char *
+print_insn_arg (d, buffer, p, addr, stream)
+ char *d;
+ unsigned char *buffer;
+ register unsigned char *p;
+ bfd_vma addr; /* PC for this arg to be relative to */
+ FILE *stream;
+{
+ register int val;
+ register int place = d[1];
+ int regno;
+ register char *regname;
+ register unsigned char *p1;
+ register double flval;
+ int flt_p;
+
+ switch (*d)
+ {
+ case 'C':
+ fprintf (stream, "ccr");
+ break;
+
+ case 'S':
+ fprintf (stream, "sr");
+ break;
+
+ case 'U':
+ fprintf (stream, "usp");
+ break;
+
+ case 'J':
+ {
+ static struct { char *name; int value; } names[]
+ = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
+ {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
+ {"msp", 0x803}, {"isp", 0x804}};
+
+ val = fetch_arg (buffer, place, 12);
+ for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+ if (names[regno].value == val)
+ {
+ fprintf (stream, names[regno].name);
+ break;
+ }
+ if (regno < 0)
+ fprintf (stream, "%d", val);
+ }
+ break;
+
+ case 'Q':
+ val = fetch_arg (buffer, place, 3);
+ if (val == 0) val = 8;
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'M':
+ val = fetch_arg (buffer, place, 8);
+ if (val & 0x80)
+ val = val - 0x100;
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'T':
+ val = fetch_arg (buffer, place, 4);
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'D':
+ fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
+ break;
+
+ case 'A':
+ fprintf (stream, "%s",
+ reg_names[fetch_arg (buffer, place, 3) + 010]);
+ break;
+
+ case 'R':
+ fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
+ break;
+
+ case 'F':
+ fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
+ break;
+
+ case 'O':
+ val = fetch_arg (buffer, place, 6);
+ if (val & 0x20)
+ fprintf (stream, "%s", reg_names [val & 7]);
+ else
+ fprintf (stream, "%d", val);
+ break;
+
+ case '+':
+ fprintf (stream, "%s@+",
+ reg_names[fetch_arg (buffer, place, 3) + 8]);
+ break;
+
+ case '-':
+ fprintf (stream, "%s@-",
+ reg_names[fetch_arg (buffer, place, 3) + 8]);
+ break;
+
+ case 'k':
+ if (place == 'k')
+ fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
+ else if (place == 'C')
+ {
+ val = fetch_arg (buffer, place, 7);
+ if ( val > 63 ) /* This is a signed constant. */
+ val -= 128;
+ fprintf (stream, "{#%d}", val);
+ }
+ else
+ fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ break;
+
+ case '#':
+ case '^':
+ p1 = buffer + (*d == '#' ? 2 : 4);
+ if (place == 's')
+ val = fetch_arg (buffer, place, 4);
+ else if (place == 'C')
+ val = fetch_arg (buffer, place, 7);
+ else if (place == '8')
+ val = fetch_arg (buffer, place, 3);
+ else if (place == '3')
+ val = fetch_arg (buffer, place, 8);
+ else if (place == 'b')
+ val = NEXTBYTE (p1);
+ else if (place == 'w')
+ val = NEXTWORD (p1);
+ else if (place == 'l')
+ val = NEXTLONG (p1);
+ else
+ fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ fprintf (stream, "#%d", val);
+ break;
+
+ case 'B':
+ if (place == 'b')
+ val = NEXTBYTE (p);
+ else if (place == 'w')
+ val = NEXTWORD (p);
+ else if (place == 'l')
+ val = NEXTLONG (p);
+ else if (place == 'g')
+ {
+ val = ((char *)buffer)[1];
+ if (val == 0)
+ val = NEXTWORD (p);
+ else if (val == -1)
+ val = NEXTLONG (p);
+ }
+ else if (place == 'c')
+ {
+ if (buffer[1] & 0x40) /* If bit six is one, long offset */
+ val = NEXTLONG (p);
+ else
+ val = NEXTWORD (p);
+ }
+ else
+ fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ print_address (addr + val, stream);
+ break;
+
+ case 'd':
+ val = NEXTWORD (p);
+ fprintf (stream, "%s@(%d)",
+ reg_names[fetch_arg (buffer, place, 3)], val);
+ break;
+
+ case 's':
+ fprintf (stream, "%s",
+ fpcr_names[fetch_arg (buffer, place, 3)]);
+ break;
+
+ case 'I':
+ val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */
+ if (val != 1) /* Unusual coprocessor ID? */
+ fprintf (stream, "(cpid=%d) ", val);
+ if (place == 'i')
+ p += 2; /* Skip coprocessor extended operands */
+ break;
+
+ case '*':
+ case '~':
+ case '%':
+ case ';':
+ case '@':
+ case '!':
+ case '$':
+ case '?':
+ case '/':
+ case '&':
+
+ if (place == 'd')
+ {
+ val = fetch_arg (buffer, 'x', 6);
+ val = ((val & 7) << 3) + ((val >> 3) & 7);
+ }
+ else
+ val = fetch_arg (buffer, 's', 6);
+
+ /* Get register number assuming address register. */
+ regno = (val & 7) + 8;
+ regname = reg_names[regno];
+ switch (val >> 3)
+ {
+ case 0:
+ fprintf (stream, "%s", reg_names[val]);
+ break;
+
+ case 1:
+ fprintf (stream, "%s", regname);
+ break;
+
+ case 2:
+ fprintf (stream, "%s@", regname);
+ break;
+
+ case 3:
+ fprintf (stream, "%s@+", regname);
+ break;
+
+ case 4:
+ fprintf (stream, "%s@-", regname);
+ break;
+
+ case 5:
+ val = NEXTWORD (p);
+ fprintf (stream, "%s@(%d)", regname, val);
+ break;
+
+ case 6:
+ p = print_indexed (regno, p, addr, stream);
+ break;
+
+ case 7:
+ switch (val & 7)
+ {
+ case 0:
+ val = NEXTWORD (p);
+ fprintf (stream, "@#");
+ print_address (val, stream);
+ break;
+
+ case 1:
+ val = NEXTLONG (p);
+ fprintf (stream, "@#");
+ print_address (val, stream);
+ break;
+
+ case 2:
+ val = NEXTWORD (p);
+ print_address (addr + val, stream);
+ break;
+
+ case 3:
+ p = print_indexed (-1, p, addr, stream);
+ break;
+
+ case 4:
+ flt_p = 1; /* Assume it's a float... */
+ switch( place )
+ {
+ case 'b':
+ val = NEXTBYTE (p);
+ flt_p = 0;
+ break;
+
+ case 'w':
+ val = NEXTWORD (p);
+ flt_p = 0;
+ break;
+
+ case 'l':
+ val = NEXTLONG (p);
+ flt_p = 0;
+ break;
+
+ case 'f':
+ flval = NEXTSINGLE(p);
+ break;
+
+ case 'F':
+ flval = NEXTDOUBLE(p);
+ break;
+
+ case 'x':
+ flval = NEXTEXTEND(p);
+ break;
+
+ case 'p':
+ flval = NEXTPACKED(p);
+ break;
+
+ default:
+ fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
+ *d, place);
+ }
+ if ( flt_p ) /* Print a float? */
+ fprintf (stream, "#%g", flval);
+ else
+ fprintf (stream, "#%d", val);
+ break;
+
+ default:
+ fprintf (stream, "<invalid address mode 0%o>", (unsigned) val);
+ }
+ }
+ break;
+
+ case 'L':
+ case 'l':
+ if (place == 'w')
+ {
+ char doneany;
+ p1 = buffer + 2;
+ val = NEXTWORD (p1);
+ /* Move the pointer ahead if this point is farther ahead
+ than the last. */
+ p = p1 > p ? p1 : p;
+ if (val == 0)
+ {
+ fputs ("#0", stream);
+ break;
+ }
+ if (*d == 'l')
+ {
+ register int newval = 0;
+ for (regno = 0; regno < 16; ++regno)
+ if (val & (0x8000 >> regno))
+ newval |= 1 << regno;
+ val = newval;
+ }
+ val &= 0xffff;
+ doneany = 0;
+ for (regno = 0; regno < 16; ++regno)
+ if (val & (1 << regno))
+ {
+ int first_regno;
+ if (doneany)
+ fputs ("/", stream);
+ doneany = 1;
+ fprintf (stream, "%s", reg_names[regno]);
+ first_regno = regno;
+ while (val & (1 << (regno + 1)))
+ ++regno;
+ if (regno > first_regno)
+ fprintf (stream, "-%s", reg_names[regno]);
+ }
+ }
+ else if (place == '3')
+ {
+ /* `fmovem' insn. */
+ char doneany;
+ val = fetch_arg (buffer, place, 8);
+ if (val == 0)
+ {
+ fputs ("#0", stream);
+ break;
+ }
+ if (*d == 'l')
+ {
+ register int newval = 0;
+ for (regno = 0; regno < 8; ++regno)
+ if (val & (0x80 >> regno))
+ newval |= 1 << regno;
+ val = newval;
+ }
+ val &= 0xff;
+ doneany = 0;
+ for (regno = 0; regno < 8; ++regno)
+ if (val & (1 << regno))
+ {
+ int first_regno;
+ if (doneany)
+ fputs ("/", stream);
+ doneany = 1;
+ fprintf (stream, "fp%d", regno);
+ first_regno = regno;
+ while (val & (1 << (regno + 1)))
+ ++regno;
+ if (regno > first_regno)
+ fprintf (stream, "-fp%d", regno);
+ }
+ }
+ else
+ abort ();
+ break;
+
+ default:
+ fprintf(stderr, "Invalid arg format in opcode table: \"%c\".", *d);
+ }
+
+ return (unsigned char *) p;
+}
+
+/* Fetch BITS bits from a position in the instruction specified by CODE.
+ CODE is a "place to put an argument", or 'x' for a destination
+ that is a general address (mode and register).
+ BUFFER contains the instruction. */
+
+static int
+fetch_arg (buffer, code, bits)
+ unsigned char *buffer;
+ char code;
+ int bits;
+{
+ register int val;
+ switch (code)
+ {
+ case 's':
+ val = buffer[1];
+ break;
+
+ case 'd': /* Destination, for register or quick. */
+ val = (buffer[0] << 8) + buffer[1];
+ val >>= 9;
+ break;
+
+ case 'x': /* Destination, for general arg */
+ val = (buffer[0] << 8) + buffer[1];
+ val >>= 6;
+ break;
+
+ case 'k':
+ val = (buffer[3] >> 4);
+ break;
+
+ case 'C':
+ val = buffer[3];
+ break;
+
+ case '1':
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 12;
+ break;
+
+ case '2':
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 6;
+ break;
+
+ case '3':
+ case 'j':
+ val = (buffer[2] << 8) + buffer[3];
+ break;
+
+ case '4':
+ val = (buffer[4] << 8) + buffer[5];
+ val >>= 12;
+ break;
+
+ case '5':
+ val = (buffer[4] << 8) + buffer[5];
+ val >>= 6;
+ break;
+
+ case '6':
+ val = (buffer[4] << 8) + buffer[5];
+ break;
+
+ case '7':
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 7;
+ break;
+
+ case '8':
+ val = (buffer[2] << 8) + buffer[3];
+ val >>= 10;
+ break;
+
+ default:
+ abort ();
+ }
+
+ switch (bits)
+ {
+ case 3:
+ return val & 7;
+ case 4:
+ return val & 017;
+ case 5:
+ return val & 037;
+ case 6:
+ return val & 077;
+ case 7:
+ return val & 0177;
+ case 8:
+ return val & 0377;
+ case 12:
+ return val & 07777;
+ default:
+ abort ();
+ return(0);
+ }
+} /* fetch_arg() */
+
+/* Print an indexed argument. The base register is BASEREG (-1 for pc).
+ P points to extension word, in buffer.
+ ADDR is the nominal core address of that extension word. */
+
+static unsigned char *
+print_indexed (basereg, p, addr, stream)
+ int basereg;
+ unsigned char *p;
+ FILE *stream;
+bfd_vma addr;
+{
+ register int word;
+ static char *scales[] = {"", "*2", "*4", "*8"};
+ register int base_disp;
+ register int outer_disp;
+ char buf[40];
+
+ word = NEXTWORD (p);
+
+ /* Generate the text for the index register.
+ Where this will be output is not yet determined. */
+ sprintf (buf, "[%s.%c%s]",
+ reg_names[(word >> 12) & 0xf],
+ (word & 0x800) ? 'l' : 'w',
+ scales[(word >> 9) & 3]);
+
+ /* Handle the 68000 style of indexing. */
+
+ if ((word & 0x100) == 0)
+ {
+ print_base (basereg,
+ ((word & 0x80) ? word | 0xff00 : word & 0xff)
+ + ((basereg == -1) ? addr : 0),
+ stream);
+ fputs (buf, stream);
+ return p;
+ }
+
+ /* Handle the generalized kind. */
+ /* First, compute the displacement to add to the base register. */
+
+ if (word & 0200)
+ basereg = -2;
+ if (word & 0100)
+ buf[0] = 0;
+ base_disp = 0;
+ switch ((word >> 4) & 3)
+ {
+ case 2:
+ base_disp = NEXTWORD (p);
+ break;
+ case 3:
+ base_disp = NEXTLONG (p);
+ }
+ if (basereg == -1)
+ base_disp += addr;
+
+ /* Handle single-level case (not indirect) */
+
+ if ((word & 7) == 0)
+ {
+ print_base (basereg, base_disp, stream);
+ fputs (buf, stream);
+ return p;
+ }
+
+ /* Two level. Compute displacement to add after indirection. */
+
+ outer_disp = 0;
+ switch (word & 3)
+ {
+ case 2:
+ outer_disp = NEXTWORD (p);
+ break;
+ case 3:
+ outer_disp = NEXTLONG (p);
+ }
+
+ fprintf (stream, "%d(", outer_disp);
+ print_base (basereg, base_disp, stream);
+
+ /* If postindexed, print the closeparen before the index. */
+ if (word & 4)
+ fprintf (stream, ")%s", buf);
+ /* If preindexed, print the closeparen after the index. */
+ else
+ fprintf (stream, "%s)", buf);
+
+ return p;
+}
+
+/* Print a base register REGNO and displacement DISP, on STREAM.
+ REGNO = -1 for pc, -2 for none (suppressed). */
+
+static void
+print_base (regno, disp, stream)
+ int regno;
+ int disp;
+ FILE *stream;
+{
+ if (regno == -2)
+ fprintf (stream, "%d", disp);
+ else if (regno == -1)
+ fprintf (stream, "0x%x", (unsigned) disp);
+ else
+ fprintf (stream, "%d(%s)", disp, reg_names[regno]);
+}
diff --git a/binutils/nm.c b/binutils/nm.c
new file mode 100644
index 0000000..ac490f7
--- /dev/null
+++ b/binutils/nm.c
@@ -0,0 +1,387 @@
+/*** nm.c -- Describe symbol table of a rel file. */
+#include "sysdep.h"
+#include "bfd.h"
+#include "getopt.h"
+#include "stab.gnu.h"
+#include <ranlib.h>
+
+
+
+PROTO(static boolean, display_file, (char *filename));
+PROTO(static boolean, do_one_rel_file, (bfd *file));
+PROTO(static unsigned int, filter_symbols, (bfd *file, asymbol **syms,
+ unsigned long symcount));
+
+PROTO(static void, print_symbols, (bfd *file, asymbol **syms,
+ unsigned long symcount));
+extern PROTO(int, (*sorters[2][2]), (char *x, char *y));
+PROTO(static void, print_symdef_entry, (bfd * abfd));
+
+/* Command options. */
+
+int external_only = 0; /* print external symbols only */
+int file_on_each_line = 0; /* print file name on each line */
+int no_sort = 0; /* don't sort; print syms in order found */
+int print_debug_syms = 0; /* print debugger-only symbols too */
+int print_armap = 0; /* describe __.SYMDEF data in archive files. */
+int reverse_sort = 0; /* sort in downward(alpha or numeric) order */
+int sort_numerically = 0; /* sort in numeric rather than alpha order */
+int undefined_only = 0; /* print undefined symbols only */
+
+boolean print_each_filename = false; /* Ick. Used in archives. */
+
+/* IMPORT */
+extern char *program_name;
+extern char *program_version;
+extern char *target;
+
+struct option long_options[] = {
+ {"debug-syms", 0, &print_debug_syms, 1},
+ {"extern-only", 0, &external_only, 1},
+ {"no-sort", 0, &no_sort, 1},
+ {"numeric-sort", 0, &sort_numerically, 1},
+ {"print-armap", 0, &print_armap, 1},
+ {"print-file-name", 0, &file_on_each_line, 1},
+ {"reverse-sort", 0, &reverse_sort, 1},
+ {"target", 2, NULL, NULL},
+ {"undefined-only", 0, &undefined_only, 1},
+ {0, 0, 0, 0}
+};
+
+/* Some error-reporting functions */
+
+void
+usage ()
+{
+ fprintf(stderr, "nm %s\nUsage: %s [-agnoprsu] filename...\n",
+ program_version, program_name);
+ exit(0);
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c; /* sez which option char */
+ int ind = 0; /* used by getopt and ignored by us */
+ extern int optind; /* steps thru options */
+
+ program_name = *argv;
+
+ while ((c = getopt_long(argc, argv, "agnoprsu", long_options, &ind)) != EOF) {
+ switch (c) {
+ case 'a': print_debug_syms = 1; break;
+ case 'g': external_only = 1; break;
+ case 'n': sort_numerically = 1; break;
+ case 'o': file_on_each_line = 1; break;
+ case 'p': no_sort = 1; break;
+ case 'r': reverse_sort = 1; break;
+ case 's': print_armap = 1; break;
+ case 'u': undefined_only = 1; break;
+
+ case 0:
+ if (!strcmp("target",(long_options[option_index]).name)) {
+ target = optarg;
+ }
+
+ break; /* we've been given a long option */
+
+ default:
+ usage ();
+ }
+ }
+
+ /* Strangely, for the shell you should return only a nonzero value
+ on sucess -- the inverse of the C sense. */
+
+ /* OK, all options now parsed. If no filename specified, do a.out. */
+ if (optind == argc) return !display_file ("a.out");
+
+ /* We were given several filenames to do: */
+ while (optind < argc)
+ if (!display_file (argv[optind++])) return 1;
+
+ return 0;
+}
+
+/** Display a file's stats */
+
+/* goto here is marginally cleaner than the nested if syntax */
+
+static boolean
+display_file (filename)
+ char *filename;
+{
+ boolean retval = false;
+ bfd *file;
+ bfd *arfile = NULL;
+
+ file = bfd_openr(filename, target);
+ if (file == NULL) {
+ bfd_fatal (filename);
+ }
+
+ if (bfd_check_format(file, bfd_object)) {
+ retval = do_one_rel_file (file);
+ goto closer;
+ }
+
+ if (!bfd_check_format (file, bfd_archive)) {
+ fprintf (stderr, "%s: %s: unknown format.\n", program_name, filename);
+ retval = false;
+ goto closer;
+ }
+
+ printf("In archive %s:\n", filename);
+ if (print_armap) print_symdef_entry (file);
+ for (;;) {
+ arfile = bfd_openr_next_archived_file (file, arfile);
+
+ if (arfile == NULL) {
+ if (bfd_error != no_more_archived_files)
+ bfd_fatal (filename);
+ goto closer;
+ }
+
+ if (!bfd_check_format(arfile, bfd_object))
+ printf("%s: not an object file\n", arfile->filename);
+ else {
+ printf ("\n%s:\n", arfile->filename);
+ if (!do_one_rel_file (arfile)) return false;
+ }
+ }
+
+ closer:
+ if (bfd_close(file) == false)
+ bfd_fatal (filename);
+
+ return retval;
+}
+
+
+static boolean
+do_one_rel_file (abfd)
+ bfd *abfd;
+{
+ unsigned int storage;
+ asymbol **syms;
+ unsigned int symcount = 0;
+
+ if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
+ (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
+ return true;
+ }
+
+
+ storage = get_symtab_upper_bound (abfd);
+ if (storage == 0) {
+ nosymz:
+ fprintf (stderr, "%s: Symflags set but there are none?\n",
+ bfd_get_filename (abfd));
+ exit (1);
+ }
+
+ syms = (asymbol **) xmalloc (storage);
+
+ symcount = bfd_canonicalize_symtab (abfd, syms);
+ if (symcount == 0) goto nosymz;
+
+ /* Discard the symbols we don't want to print.
+ It's OK to do this in place; we'll free the storage anyway
+ (after printing) */
+
+ symcount = filter_symbols (abfd, syms, symcount);
+
+ if (!no_sort)
+ qsort((char *) syms, symcount, sizeof (asymbol *),
+ sorters[sort_numerically][reverse_sort]);
+
+ if (print_each_filename && !file_on_each_line)
+ printf("\n%s:\n", bfd_get_filename(abfd));
+
+ print_symbols (abfd, syms, symcount);
+ free (syms);
+ return true;
+}
+
+/* Symbol-sorting predicates */
+#define valueof(x) ((x)->section ? (x)->section->vma + (x)->value : (x)->value)
+int
+numeric_forward (x, y)
+ char *x;
+ char *y;
+{
+
+ return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));;
+}
+
+int
+numeric_reverse (x, y)
+ char *x;
+ char *y;
+{
+ return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x));
+
+}
+
+int
+non_numeric_forward (x, y)
+ char *x;
+ char *y;
+{
+ char *xn = (*(asymbol **) x)->name;
+ char *yn = (*(asymbol **) y)->name;
+
+ return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) :
+ ((yn == NULL) ? 1 : strcmp (xn, yn)));
+}
+
+int
+non_numeric_reverse (x, y)
+ char *x;
+ char *y;
+{
+ return -(non_numeric_forward (x, y));
+}
+
+int (*sorters[2][2])() = {
+ {non_numeric_forward, non_numeric_reverse},
+ {numeric_forward, numeric_reverse},
+};
+
+
+/* Choose which symbol entries to print;
+ compact them downward to get rid of the rest.
+ Return the number of symbols to be printed. */
+static unsigned int
+filter_symbols (abfd, syms, symcount)
+ bfd *abfd;
+ asymbol **syms;
+ unsigned long symcount;
+{
+ asymbol **from, **to;
+ unsigned int dst_count = 0;
+ unsigned int src_count;
+ for (from = to = syms, src_count = 0; src_count <symcount; src_count++) {
+ int keep = 0;
+ flagword flags = (from[src_count])->flags;
+
+ if (undefined_only) {
+ keep = (flags & BSF_UNDEFINED);
+ } else if (external_only) {
+ keep = ((flags & BSF_GLOBAL) || (flags & BSF_UNDEFINED) ||
+ (flags & BSF_FORT_COMM));
+ } else {
+ keep = 1;
+ }
+
+ if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) {
+ keep = 0;
+ }
+
+ if (keep) {
+ to[dst_count++] = from[src_count];
+ }
+ }
+
+ return dst_count;
+}
+
+
+/* Return a lower-case character corresponding to the symbol class of sym */
+char
+decode_symclass (sym)
+ asymbol *sym;
+{
+ flagword flags = sym->flags;
+
+ if ((sym->value == 0) && (sym->section != NULL))
+ /* Huh? All section names don't begin with "." */
+ return (sym->section->name)[1];
+
+ if (flags & BSF_FORT_COMM) return 'C';
+ if (flags & BSF_UNDEFINED) return 'U';
+ if (flags & BSF_ABSOLUTE) return 'a';
+
+
+ if ( (flags & BSF_GLOBAL) || (flags & BSF_LOCAL) ){
+ if ( !strcmp(sym->section->name, ".text") ){
+ return 't';
+ } else if ( !strcmp(sym->section->name, ".data") ){
+ return 'd';
+ } else if ( !strcmp(sym->section->name, ".bss") ){
+ return 'b';
+ } else {
+ return 'o';
+ }
+ }
+
+ /* We don't have to handle these cases just yet, but we will soon:
+ N_SETV: 'v';
+ N_SETA: 'l';
+ N_SETT: 'x';
+ N_SETD: 'z';
+ N_SETB: 's';
+ N_INDR: 'i';
+ */
+
+ return '?';
+}
+
+static void
+print_symbols (abfd, syms, symcount)
+ bfd *abfd;
+ asymbol **syms;
+ unsigned long symcount;
+{
+ asymbol **sym = syms, **end = syms + symcount;
+ char class;
+
+ for (; sym < end; ++sym) {
+ if (file_on_each_line) printf("%s:", bfd_get_filename(abfd));
+
+ if (undefined_only) {
+ if ((*sym)->flags & BSF_UNDEFINED)
+ puts ((*sym)->name);
+ }
+ else {
+ asymbol *p = *sym;
+ if (p) {
+ class = decode_symclass (p);
+
+ if (p->flags & BSF_GLOBAL)
+ class = toupper (class);
+
+ if (p->value || ((p->flags & BSF_UNDEFINED) != BSF_UNDEFINED))
+ printf ("%08lx ", (p->section ? p->value + p->section->vma : p->value));
+ else fputs (" ", stdout);
+
+ printf ("%c %s\n", class, p->name);
+ }
+ }
+ }
+}
+
+static void
+print_symdef_entry (abfd)
+ bfd * abfd;
+{
+ symindex idx = BFD_NO_MORE_SYMBOLS;
+ carsym *thesym;
+ boolean everprinted = false;
+
+ for (idx = bfd_get_next_mapent (abfd, idx, &thesym);
+ idx != BFD_NO_MORE_SYMBOLS;
+ idx = bfd_get_next_mapent (abfd, idx, &thesym)) {
+ bfd *elt;
+ if (!everprinted) {
+ printf ("\nArchive index:\n");
+ everprinted = true;
+ }
+ elt = bfd_get_elt_at_index (abfd, idx);
+ if (thesym->name != (char *)NULL) {
+ printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
+}
+ }
+}
diff --git a/binutils/objdump.c b/binutils/objdump.c
new file mode 100644
index 0000000..352adc3
--- /dev/null
+++ b/binutils/objdump.c
@@ -0,0 +1,714 @@
+/*** objdump.c -- dump information about an object file. */
+
+/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Diddler.
+
+BFD is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+BFD is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BFD; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ $Id$
+ $Log$
+ Revision 1.1 1991/03/21 21:26:48 gumby
+ Initial revision
+
+ * Revision 1.2 1991/03/15 18:34:14 rich
+ * foo
+ *
+ * Revision 1.1 1991/03/13 00:34:19 chrisb
+ * Initial revision
+ *
+ * Revision 1.9 1991/03/09 04:36:33 rich
+ * Modified Files:
+ * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
+ * binutils.h
+ *
+ * Pulled sysdep.h out of bfd.h.
+ *
+ * Revision 1.8 1991/03/09 03:42:01 rich
+ * Modified Files:
+ * Makefile alloca.c ar.c i960-pinsn.c nm.c objdump.c ostrip.c
+ * strip.c
+ *
+ * Ports for intel960 group Portland.
+ *
+ * Revision 1.7 1991/03/08 21:54:47 rich
+ * Modified Files:
+ * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
+ * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
+ * sparc-pinsn.c strip.c
+ *
+ * Verifying Portland tree with steve's last changes. Also, some partial
+ * porting.
+ *
+ * Revision 1.6 1991/03/08 07:46:26 sac
+ * Added -l option to disassembly - prints line numbers too.
+ *
+ * Revision 1.5 1991/03/07 21:50:24 sac
+ * More intelligent reloc printing
+ *
+ * Revision 1.4 1991/03/05 16:36:54 sac
+ * Fixed bug where empty symbols would print (null) on suns and crash elsewhere.
+ *
+*/
+/*
+ * Until there is other documentation, refer to the manual page dump(1) in
+ * the system 5 program's reference manual
+ */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "getopt.h"
+#include <stdio.h>
+#include <ctype.h>
+
+char *malloc();
+char *realloc();
+char *xmalloc();
+
+char *default_target = NULL; /* default at runtime */
+
+char *program_name = NULL;
+
+int dump_section_contents; /* -s */
+int dump_section_headers; /* -h */
+boolean dump_file_header; /* -f */
+int dump_symtab; /* -t */
+int dump_reloc_info; /* -r */
+int dump_ar_hdrs; /* -a */
+int with_line_numbers; /* -l */
+boolean disassemble; /* -d */
+char *only;
+
+PROTO (void, display_file, (char *filename, char *target));
+PROTO (void, dump_data, (bfd *abfd));
+PROTO (void, dump_relocs, (bfd *abfd));
+PROTO (void, dump_symbols, (bfd *abfd));
+PROTO (void, print_arelt_descr, (bfd *abfd, boolean verbose));
+
+
+
+
+
+
+
+char *machine = (char *)NULL;
+ asymbol **syms;
+ asymbol **syms2;
+
+
+unsigned int storage;
+
+unsigned int symcount = 0;
+
+void
+usage ()
+{
+ fprintf (stderr,
+ "usage: %s [-ahfdrtxsl] [-m machine] [-j section_name] obj ...\n",
+ program_name);
+ exit (1);
+}
+
+static struct option long_options[] =
+ {{"syms", 0, &dump_symtab, 1},
+ {"reloc", 0, &dump_reloc_info, 1},
+ {"header", 0, &dump_section_headers, 1},
+ {0, 0, 0, 0}};
+
+
+
+static void
+dump_headers(abfd)
+bfd *abfd;
+{
+ asection *section;
+ for (section = abfd->sections;
+ section != (asection *) NULL;
+ section = section->next)
+ {
+ char *comma = "";
+#define PF(x,y) \
+ if (section->flags & x) { printf("%s%s",comma,y); comma = ", "; }
+
+ printf("SECTION %d [%s]\t: size %08x",
+ section->index,
+ section->name,
+(unsigned) section->size);
+ printf(" vma %08lx align 2**%2u\n ",
+ section->vma,
+ section->alignment_power);
+ PF(SEC_ALLOC,"ALLOC");
+ PF(SEC_LOAD,"LOAD");
+ PF(SEC_RELOC,"RELOC");
+ PF(SEC_BALIGN,"BALIGN");
+ PF(SEC_READONLY,"READONLY");
+ PF(SEC_CODE,"CODE");
+ PF(SEC_DATA,"DATA");
+ PF(SEC_ROM,"ROM");
+ printf("\n");
+#undef PF
+ }
+}
+
+static asymbol **
+slurp_symtab(abfd)
+bfd *abfd;
+{
+ asymbol **sy;
+ if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
+ (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
+ return(NULL);
+ }
+
+ storage = get_symtab_upper_bound (abfd);
+ if (storage) {
+ sy = (asymbol **) malloc (storage);
+ if (sy == NULL) {
+ fprintf (stderr, "%s: out of memory.\n", program_name);
+ exit (1);
+ }
+ }
+ symcount = bfd_canonicalize_symtab (abfd, sy);
+return sy;
+}
+/* Sort symbols into value order */
+static int comp(ap,bp)
+asymbol **ap;
+asymbol **bp;
+{
+ asymbol *a = *ap;
+ asymbol *b = *bp;
+ int diff;
+
+ if ( a->name== (char *)NULL || (a->flags &( BSF_DEBUGGING| BSF_UNDEFINED) ))
+ a->the_bfd = 0;
+ if ( b->name== (char *)NULL || (b->flags &( BSF_DEBUGGING|BSF_UNDEFINED)))
+ b->the_bfd =0;
+
+ diff = a->the_bfd - b->the_bfd;
+ if (diff) {
+ return -diff;
+ }
+ diff = a->value - b->value;
+ if (diff) {
+ return diff;
+ }
+ return a->section - b->section;
+}
+
+/* Print the supplied address symbolically if possible */
+void
+print_address(vma, stream)
+bfd_vma vma;
+FILE *stream;
+{
+ /* Perform a binary search looking for the closest symbol to
+ the required value */
+
+ unsigned int min = 0;
+ unsigned int max = symcount;
+
+ unsigned int thisplace = 1;
+ unsigned int oldthisplace ;
+
+ int vardiff;
+ if (symcount == 0)
+ fprintf(stream,"%08lx", vma);
+ else {
+ while (true) {
+ oldthisplace = thisplace;
+ thisplace = (max + min )/2 ;
+ if (thisplace == oldthisplace) break;
+
+
+ vardiff = syms[thisplace]->value - vma;
+
+ if (vardiff) {
+ if (vardiff > 0) {
+ max = thisplace;
+ }
+ else {
+ min = thisplace;
+ }
+ }
+ else {
+ /* Totally awesome! the exact right symbol */
+ fprintf(stream,"%08lx (%s)", vma, syms[thisplace]->name);
+ return;
+ }
+ }
+ /* We've run out of places to look, print the symbol before this one */
+ /* see if this or the symbol before describes this location the best */
+
+ if (thisplace != 0) {
+ if (syms[thisplace-1]->value - vma >
+ syms[thisplace]->value-vma) {
+ /* Previous symbol is in correct section and is closer */
+ thisplace --;
+ }
+ }
+
+ {
+ char *section_name;
+ asection *sec = syms[thisplace]->section;
+ if (sec) {
+ section_name = sec->name;
+ }
+ else {
+ section_name = "abs";
+ }
+ }
+ if (syms[thisplace]->value > vma) {
+ fprintf(stream,"%08lx (%s-%lx)", vma, syms[thisplace]->name,
+ syms[thisplace]->value - vma);
+
+ }
+ else {
+ fprintf(stream,"%08lx (%s+%lx)", vma,
+ syms[thisplace]->name,
+ vma - syms[thisplace]->value);
+ }
+ }
+}
+
+void
+disassemble_data(abfd)
+bfd *abfd;
+{
+ bfd_byte *data = NULL;
+ unsigned int datasize = 0;
+ unsigned int i;
+ int (*print)() ;
+ int print_insn_m68k();
+ int print_insn_i960();
+ int print_insn_sparc();
+ enum bfd_architecture a;
+ unsigned long m;
+ asection *section;
+ /* Replace symbol section relative values with abs values */
+
+
+ for (i = 0; i < symcount; i++) {
+ if (syms[i]->section != (asection *)NULL) {
+ syms[i]->value += syms[i]->section->vma;
+ }
+ }
+
+ /* We keep a copy of the symbols in the original order */
+ syms2 = slurp_symtab(abfd);
+
+ /* Sort the symbols into section and symbol order */
+ (void) qsort(syms, symcount, sizeof(asymbol *), comp);
+
+ /* Find the first useless symbol */
+ { unsigned int i;
+ for (i =0; i < symcount; i++) {
+ if (syms[i]->the_bfd == 0) {
+ symcount =i;
+ break;
+ }
+ }
+ }
+
+
+ if (machine!= (char *)NULL) {
+ if (bfd_scan_arch_mach(machine, &a, &m) == false) {
+ fprintf(stderr,"%s: Can't use supplied machine %s\n",
+ program_name,
+ machine);
+ exit(1);
+ }
+ }
+ else {
+ a = bfd_get_architecture(abfd);
+ }
+ switch (a) {
+
+ case bfd_arch_sparc:
+ print = print_insn_sparc;
+ break;
+ case bfd_arch_m68k:
+ print = print_insn_m68k;
+ break;
+ case bfd_arch_i960:
+ print = print_insn_i960;
+ break;
+ default:
+ fprintf(stderr,"%s: Can't disassemble for architecture %s\n",
+ program_name,
+ bfd_printable_arch_mach(bfd_get_architecture(abfd),0));
+ exit(1);
+ }
+
+
+ for (section = abfd->sections;
+ section != (asection *)NULL;
+ section = section->next) {
+
+ if (only == (char *)NULL || strcmp(only,section->name) == 0){
+ printf("Disassembly of section %s:\n", section->name);
+
+ if (section->size == 0) continue;
+
+ data = (bfd_byte *)malloc(section->size);
+
+ if (data == (bfd_byte *)NULL) {
+ fprintf (stderr, "%s: memory exhausted.\n", program_name);
+ exit (1);
+ }
+ datasize = section->size;
+
+
+ bfd_get_section_contents (abfd, section, data, 0, section->size);
+
+ i = 0;
+ while ((size_t)i <section->size) {
+ if (with_line_numbers) {
+ static prevline;
+ char *filename;
+ char *functionname;
+ int line;
+ bfd_find_nearest_line(abfd,
+ section,
+ syms,
+ section->vma + i,
+ &filename,
+ &functionname,
+ &line);
+
+ if (filename && functionname && line && line != prevline) {
+ printf("%s:%d\n", filename, line);
+ prevline = line;
+ }
+ }
+ print_address(section->vma + i, stdout);
+ printf(" ");
+
+ i += print(section->vma + i,
+ data + i,
+ stdout);
+ putchar ('\n') ;
+ }
+
+
+
+
+ free(data);
+ }
+ }
+}
+
+void
+display_bfd (abfd)
+ bfd *abfd;
+{
+
+ if (!bfd_check_format (abfd, bfd_object)) {
+ fprintf (stderr,"%s: %s not an object file\n", program_name,
+ abfd->filename);
+ return;
+ }
+ printf ("\n%s: file format %s\n", abfd->filename, abfd->xvec->name);
+ if (dump_ar_hdrs) print_arelt_descr (abfd, true);
+
+ if (dump_file_header) {
+ char *comma = "";
+
+ printf("architecture: %s, ",
+ bfd_printable_arch_mach (bfd_get_architecture (abfd),
+ bfd_get_machine (abfd)));
+ printf("flags 0x%08x:\n", abfd->flags);
+
+#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";}
+ PF(HAS_RELOC, "HAS_RELOC");
+ PF(EXEC_P, "EXEC_P");
+ PF(HAS_LINENO, "HAS_LINENO");
+ PF(HAS_DEBUG, "HAS_DEBUG");
+ PF(HAS_SYMS, "HAS_SYMS");
+ PF(HAS_LOCALS, "HAS_LOCALS");
+ PF(DYNAMIC, "DYNAMIC");
+ PF(WP_TEXT, "WP_TEXT");
+ PF(D_PAGED, "D_PAGED");
+ printf("\nstart address 0x%08lx", abfd->start_address);
+ }
+ printf("\n");
+
+ if (dump_section_headers)
+ dump_headers(abfd);
+ if (dump_symtab || dump_reloc_info || disassemble) {
+syms = slurp_symtab(abfd);
+ }
+ if (dump_symtab) dump_symbols (abfd);
+ if (dump_reloc_info) dump_relocs(abfd);
+ if (dump_section_contents) dump_data (abfd);
+ if (disassemble) disassemble_data(abfd);
+}
+
+void
+display_file (filename, target)
+ char *filename;
+ char *target;
+{
+ bfd *file, *arfile = (bfd *) NULL;
+
+ file = bfd_openr (filename, target);
+ if (file == NULL) {
+ bfd_perror (filename);
+ return;
+ }
+
+ if (bfd_check_format (file, bfd_archive) == true) {
+ printf ("In archive %s:\n", bfd_get_filename (file));
+ for(;;) {
+ bfd_error = no_error;
+
+ arfile = bfd_openr_next_archived_file (file, arfile);
+ if (arfile == NULL) {
+ if (bfd_error != no_more_archived_files)
+ bfd_perror (bfd_get_filename(file));
+ return;
+ }
+
+ display_bfd (arfile);
+ /* Don't close the archive elements; we need them for next_archive */
+ }
+ }
+ else
+ display_bfd(file);
+
+ bfd_close(file);
+}
+
+/* Actually display the various requested regions */
+
+
+
+
+
+
+
+
+
+
+void
+dump_data (abfd)
+ bfd *abfd;
+{
+ asection *section;
+ bfd_byte *data ;
+ unsigned int datasize = 0;
+ size_t i;
+
+ for (section = abfd->sections; section != NULL; section =
+ section->next) {
+ int onaline = 16;
+
+ if (only == (char *)NULL ||
+ strcmp(only,section->name) == 0){
+
+
+
+ printf("Contents of section %s:\n", section->name);
+
+ if (section->size == 0) continue;
+ data = (bfd_byte *)malloc(section->size);
+ if (data == (bfd_byte *)NULL) {
+ fprintf (stderr, "%s: memory exhausted.\n", program_name);
+ exit (1);
+ }
+ datasize = section->size;
+
+
+ bfd_get_section_contents (abfd, section, data, 0, section->size);
+
+ for (i= 0; i < section->size; i += onaline) {
+ size_t j;
+ printf(" %04lx ", i + section->vma);
+ for (j = i; j < i+ onaline; j++) {
+ if (j < section->size)
+ printf("%02x", (unsigned)(data[j]));
+ else
+ printf(" ");
+ if ((j & 3 ) == 3) printf(" ");
+ }
+
+ printf(" ");
+ for (j = i; j < i+onaline ; j++) {
+ if (j >= section->size)
+ printf(" ");
+ else
+ printf("%c", isprint(data[j]) ?data[j] : '.');
+ }
+ putchar ('\n');
+ }
+ }
+
+ free (data);
+ }
+}
+
+
+
+/* Should perhaps share code and display with nm? */
+void
+dump_symbols (abfd)
+ bfd *abfd;
+{
+
+ unsigned int count;
+ asymbol **current = syms;
+ printf("SYMBOL TABLE:\n");
+
+ for (count = 0; count < symcount; count++) {
+ if ((*current)->the_bfd) {
+ bfd_print_symbol((*current)->the_bfd,
+ stdout,
+ *current, bfd_print_symbol_all_enum);
+
+ printf("\n");
+ }
+ current++;
+ }
+ printf("\n");
+ printf("\n");
+}
+
+
+void
+dump_relocs(abfd)
+bfd *abfd;
+{
+ arelent **relpp;
+ unsigned int relcount;
+ asection *a;
+ for (a = abfd->sections; a != (asection *)NULL; a = a->next) {
+ printf("RELOCATION RECORDS FOR [%s]:",a->name);
+
+ if (get_reloc_upper_bound(abfd, a) == 0) {
+ printf(" (none)\n\n");
+ }
+ else {
+ arelent **p;
+
+ relpp = (arelent **) xmalloc( get_reloc_upper_bound(abfd,a) );
+ relcount = bfd_canonicalize_reloc(abfd,a,relpp, syms);
+ if (relcount == 0) {
+ printf(" (none)\n\n");
+ }
+ else {
+ printf("\n");
+ printf("OFFSET TYPE VALUE \n");
+
+ for (p =relpp; *p != (arelent *)NULL; p++) {
+ arelent *q = *p;
+ char *sym_name;
+ char *section_name = q->section == (asection *)NULL ? "*abs" :
+ q->section->name;
+ if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
+ sym_name = (*(q->sym_ptr_ptr))->name ;
+ }
+ else {
+ sym_name = 0;
+ }
+ if (sym_name) {
+ printf("%08lx %-8s %s",
+ q->address,
+ q->howto->name,
+ sym_name);
+ }
+ else {
+ printf("%08lx %-8s [%s]",
+ q->address,
+ q->howto->name,
+ section_name);
+ }
+ if (q->addend) {
+ printf("+0x%lx(%ld)", q->addend, (long) q->addend);
+ }
+ printf("\n");
+ }
+ printf("\n\n");
+ free(relpp);
+ }
+ }
+
+ }
+}
+
+
+/** main and like trivia */
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ extern int optind;
+ extern char *optarg;
+ char *target = default_target;
+ boolean seenflag = false;
+ int ind = 0;
+
+ program_name = *argv;
+
+ while ((c = getopt_long (argc, argv, "b:m:dlfahrtxsj:", long_options, &ind))
+ != EOF) {
+ seenflag = true;
+ switch (c) {
+ case 'm':
+ machine = optarg;
+ break;
+ case 'j':
+ only = optarg;
+ break;
+ case 'l':
+ with_line_numbers = 1;
+ break;
+ case 'b':
+ target = optarg;
+ break;
+ case 'f':
+ dump_file_header = true;
+ break;
+ case 'x':
+ dump_symtab = 1;
+ dump_reloc_info = 1;
+ dump_file_header = true;
+ dump_ar_hdrs = 1;
+ dump_section_headers = 1;
+ break;
+ case 0 : break; /* we've been given a long option */
+ case 't': dump_symtab = 1; break;
+ case 'd': disassemble = true ; break;
+ case 's': dump_section_contents = 1; break;
+ case 'r': dump_reloc_info = 1; break;
+ case 'a': dump_ar_hdrs = 1; break;
+ case 'h': dump_section_headers = 1; break;
+ default:
+ usage ();
+ }
+ }
+
+ if (seenflag == false)
+ usage ();
+
+ if (optind == argc)
+ display_file ("a.out", target);
+ else
+ for (; optind < argc;)
+ display_file (argv[optind++], target);
+ return 0;
+}
diff --git a/binutils/size.c b/binutils/size.c
new file mode 100644
index 0000000..9f6800c
--- /dev/null
+++ b/binutils/size.c
@@ -0,0 +1,320 @@
+/*** size.c -- report size of various sections of an executable file */
+/* Extensions/incompatibilities:
+ o - BSD output has filenames at the end.
+ o - BSD output can appear in different radicies.
+ o - SysV output has less redundant whitespace. Filename comes at end.
+ o - SysV output doesn't show VMA which is always the same as the PMA.
+ o - We also handle core files.
+ o - We also handle archives.
+ If you write shell scripts which manipulate this info then you may be
+ out of luck; there's no +predantic switch.
+*/
+#include "sysdep.h"
+#include "bfd.h"
+#include "getopt.h"
+
+
+#ifndef BSD_DEFAULT
+#define BSD_DEFAULT 1
+#endif
+
+PROTO(void, display_file, (char *filename));
+PROTO(void, print_sizes, (bfd *file));
+
+/* Various program options */
+
+enum {decimal, octal, hex} radix = decimal;
+int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output */
+int show_version = 0;
+int show_help = 0;
+
+/* IMPORTS */
+extern char *program_version;
+extern char *program_name;
+extern char *target;
+
+/** main and like trivia */
+
+void
+usage ()
+{
+ fprintf (stderr, "size %s\nUsage: %s -{dox}{AB}V files ...\n",
+ program_version, program_name);
+ fputs("\t+radix={8|10|16} -- select appropriate output radix.\n\
+\t-d -- output in decimal\n\
+\t-o -- output in octal\n\
+\t-x -- output in hex", stderr);
+ fputs("\t+format={Berkeley|SysV} -- select display format.\n\
+\t-A -- SysV(AT&T) format\n\
+\t-B -- BSD format", stderr);
+#if BSD_DEFAULT
+ fputs("\t (Default is +format=Berkeley)", stderr);
+#else
+ fputs("\t (Default is +format=SysV)", stderr);
+#endif
+ fputs("\t-V, +version -- display program version, etc.\n\
+\t+help -- this message\n", stderr);
+ exit(1);
+}
+
+struct option long_options[] = {{"radix", 1, 0, 0},
+ {"format", 1, 0, 0},
+ {"version", 0, &show_version, 1},
+ {"target", 2, NULL, NULL},
+ {"help", 0, &show_help, 1},
+ {0, 0, 0, 0}};
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int temp;
+ int c; /* sez which option char */
+ int option_index = 0;
+ extern int optind; /* steps thru options */
+ program_name = *argv;
+
+ while ((c = getopt_long(argc, argv, "ABVdox", long_options,
+ &option_index)) != EOF)
+ switch(c) {
+ case 0:
+ if (!strcmp("format",(long_options[option_index]).name)) {
+ switch(*optarg) {
+ case 'B': case 'b': berkeley_format = 1; break;
+ case 'S': case 's': berkeley_format = 0; break;
+ default: printf("Unknown option to +format: %s\n", optarg);
+ usage();
+ }
+ break;
+ }
+
+ if (!strcmp("target",(long_options[option_index]).name)) {
+ target = optarg;
+ break;
+ }
+
+ if (!strcmp("radix",(long_options[option_index]).name)) {
+#ifdef ANSI_LIBRARIES
+ temp = strtol(optarg, NULL, 10);
+#else
+ temp = atol(optarg);
+#endif
+ switch(temp) {
+ case 10: radix = decimal; break;
+ case 8: radix = octal; break;
+ case 16: radix = hex; break;
+ default: printf("Unknown radix: %s\n", optarg);
+ usage();
+ }
+ }
+ break;
+ case 'A': berkeley_format = 0; break;
+ case 'B': berkeley_format = 1; break;
+ case 'V': show_version = 1; break;
+ case 'd': radix = decimal; break;
+ case 'x': radix = hex; break;
+ case 'o': radix = octal; break;
+ case '?': usage();
+ }
+
+ if (show_version) printf("%s version %s\n", program_name, program_version);
+ if (show_help) usage();
+
+ if (berkeley_format)
+#if 0 /* intel doesn't like bss/stk b/c they don't gave core files */
+ puts((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" :
+ "text\tdata\tbss/stk\tdec\thex\tfilename");
+#else
+ puts((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" :
+ "text\tdata\tbss\tdec\thex\tfilename");
+#endif
+ if (optind == argc)
+ display_file ("a.out");
+ else
+ for (; optind < argc;)
+ display_file (argv[optind++]);
+
+ return 0;
+}
+
+/** Display a file's stats */
+
+void
+display_bfd (abfd)
+ bfd *abfd;
+{
+ char *core_cmd;
+
+ if (bfd_check_format(abfd, bfd_archive)) return;
+
+ if (bfd_check_format(abfd, bfd_object)) {
+ print_sizes(abfd);
+ goto done;
+ }
+
+ if (bfd_check_format(abfd, bfd_core)) {
+ print_sizes(abfd);
+ fputs(" (core file", stdout);
+
+ core_cmd = bfd_core_file_failing_command(abfd);
+ if (core_cmd) printf(" invoked as %s", core_cmd);
+
+ puts(")");
+ goto done;
+ }
+
+ printf("Unknown file format: %s.", bfd_get_filename(abfd));
+
+ done:
+
+
+ printf("\n");
+ return;
+}
+
+void
+display_file(filename)
+ char *filename;
+{
+ bfd *file, *arfile = (bfd *) NULL;
+
+ file = bfd_openr (filename, target);
+ if (file == NULL) {
+ bfd_perror (filename);
+ return;
+ }
+
+ if (bfd_check_format(file, bfd_archive) == true) {
+ for(;;) {
+
+ bfd_error = no_error;
+
+ arfile = bfd_openr_next_archived_file (file, arfile);
+ if (arfile == NULL) {
+ if (bfd_error != no_more_archived_files)
+ bfd_perror (bfd_get_filename (file));
+ return;
+ }
+
+ display_bfd (arfile);
+ /* Don't close the archive elements; we need them for next_archive */
+ }
+ }
+ else
+ display_bfd (file);
+
+ bfd_close (file);
+}
+
+/* This is what lexical functions are for */
+void
+lprint_number (width, num)
+ int width, num;
+{
+ printf ((radix == decimal ? "%-*d\t" :
+ ((radix == octal) ? "%-*o\t" : "%-*x\t")), width, num);
+}
+
+void
+rprint_number(width, num)
+ int width, num;
+{
+ printf ((radix == decimal ? "%*d\t" :
+ ((radix == octal) ? "%*o\t" : "%*x\t")), width, num);
+}
+
+static char *bss_section_name = ".bss";
+static char *data_section_name = ".data";
+static char *stack_section_name = ".stack";
+static char *text_section_name = ".text";
+
+void print_berkeley_format(abfd)
+bfd *abfd;
+{
+ sec_ptr bsssection = NULL;
+ sec_ptr datasection = NULL;
+ sec_ptr textsection = NULL;
+ unsigned long bsssize = 0;
+ unsigned long datasize = 0;
+ unsigned long textsize = 0;
+ unsigned long total = 0;
+
+
+ if ((textsection = bfd_get_section_by_name (abfd, text_section_name))
+ != NULL) {
+ textsize = bfd_section_size (abfd, textsection);
+ }
+
+ if ((datasection = bfd_get_section_by_name (abfd, data_section_name))
+ != NULL) {
+ datasize = bfd_section_size(abfd, datasection);
+ }
+
+ if (bfd_get_format (abfd) == bfd_object) {
+ if ((bsssection = bfd_get_section_by_name (abfd, bss_section_name))
+ != NULL) {
+ bsssize = bfd_section_size(abfd, bsssection);
+ }
+ } else {
+ if ((bsssection = bfd_get_section_by_name (abfd, stack_section_name))
+ != NULL) {
+ bsssize = bfd_section_size(abfd, bsssection);
+ }
+ }
+
+ total = textsize + datasize + bsssize;
+
+ lprint_number (7, textsize);
+ lprint_number (7, datasize);
+ lprint_number (7, bsssize);
+ printf (((radix == octal) ? "%-7o\t%-7x\t" : "%-7d\t%-7x\t"), total, total);
+
+ fputs(bfd_get_filename(abfd), stdout);
+ if (abfd->my_archive) printf (" (ex %s)", abfd->my_archive->filename);
+}
+
+/* I REALLY miss lexical functions! */
+int svi_total = 0;
+
+void
+sysv_internal_printer(file, sec)
+ bfd *file;
+ sec_ptr sec;
+{
+ int size = bfd_section_size (file, sec);
+
+ svi_total += size;
+
+ printf ("%-12s", bfd_section_name(file, sec));
+ rprint_number (8, size);
+ printf(" ");
+ rprint_number (8, bfd_section_vma(file, sec));
+ printf ("\n");
+}
+
+void
+print_sysv_format(file)
+ bfd *file;
+{
+ svi_total = 0;
+
+ printf ("%s ", bfd_get_filename (file));
+ if (file->my_archive) printf (" (ex %s)", file->my_archive->filename);
+
+ puts(":\nsection\t\tsize\t addr");
+ bfd_map_over_sections (file, sysv_internal_printer, NULL);
+
+ printf("Total ");
+ rprint_number(8, svi_total);
+ printf("\n"); printf("\n");
+}
+
+void
+print_sizes(file)
+ bfd *file;
+{
+ if (berkeley_format)
+ print_berkeley_format(file);
+ else print_sysv_format(file);
+}
diff --git a/binutils/sparc-pinsn.c b/binutils/sparc-pinsn.c
new file mode 100644
index 0000000..550722b
--- /dev/null
+++ b/binutils/sparc-pinsn.c
@@ -0,0 +1,490 @@
+/* disassemble sparc instructions for objdump
+ Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
+
+
+This file is part of the binutils.
+
+The binutils are free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+The binutils are distributed in the hope that they will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the binutils; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* $Id$
+ $Log$
+ Revision 1.1 1991/03/21 21:26:55 gumby
+ Initial revision
+
+ * Revision 1.1 1991/03/13 00:34:40 chrisb
+ * Initial revision
+ *
+ * Revision 1.3 1991/03/09 04:36:31 rich
+ * Modified Files:
+ * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
+ * binutils.h
+ *
+ * Pulled sysdep.h out of bfd.h.
+ *
+ * Revision 1.2 1991/03/08 21:54:53 rich
+ * Modified Files:
+ * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
+ * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
+ * sparc-pinsn.c strip.c
+ *
+ * Verifying Portland tree with steve's last changes. Also, some partial
+ * porting.
+ *
+ * Revision 1.1 1991/02/22 16:48:04 sac
+ * Initial revision
+ *
+*/
+
+#include <stdio.h>
+#include "sysdep.h"
+#include "bfd.h"
+#include "sparc-opcode.h"
+
+extern int fputs();
+extern int print_address();
+
+static char *reg_names[] =
+ { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
+ "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
+ "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
+ "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+ "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" };
+
+#define freg_names (&reg_names[4 * 8])
+
+union sparc_insn
+ {
+ unsigned long int code;
+ struct
+ {
+ unsigned int OP:2;
+#define op ldst.OP
+ unsigned int RD:5;
+#define rd ldst.RD
+ unsigned int op3:6;
+ unsigned int RS1:5;
+#define rs1 ldst.RS1
+ unsigned int i:1;
+ unsigned int ASI:8;
+#define asi ldst.ASI
+ unsigned int RS2:5;
+#define rs2 ldst.RS2
+#define shcnt rs2
+ } ldst;
+ struct
+ {
+ unsigned int OP:2, RD:5, op3:6, RS1:5, i:1;
+ unsigned int IMM13:13;
+#define imm13 IMM13.IMM13
+ } IMM13;
+ struct
+ {
+ unsigned int OP:2;
+ unsigned int a:1;
+ unsigned int cond:4;
+ unsigned int op2:3;
+ unsigned int DISP22:22;
+#define disp22 branch.DISP22
+ } branch;
+#define imm22 disp22
+ struct
+ {
+ unsigned int OP:2;
+ unsigned int DISP30:30;
+#define disp30 call.DISP30
+ } call;
+ };
+
+/* Nonzero if INSN is the opcode for a delayed branch. */
+static int
+is_delayed_branch (insn)
+ union sparc_insn insn;
+{
+ unsigned int i;
+
+ for (i = 0; i < NUMOPCODES; ++i)
+ {
+ const struct sparc_opcode *opcode = &sparc_opcodes[i];
+ if ((opcode->match & insn.code) == opcode->match
+ && (opcode->lose & insn.code) == 0
+ && (opcode->delayed))
+ return 1;
+ }
+ return 0;
+}
+
+static int opcodes_sorted = 0;
+
+/* Print one instruction from MEMADDR on STREAM. */
+int
+print_insn_sparc (memaddr, buffer, stream)
+ bfd_vma memaddr;
+ bfd_byte *buffer;
+ FILE *stream;
+
+{
+ union sparc_insn insn;
+
+ register unsigned int i;
+
+ if (!opcodes_sorted)
+ {
+ static int compare_opcodes ();
+ qsort ((char *) sparc_opcodes, NUMOPCODES,
+ sizeof (sparc_opcodes[0]), compare_opcodes);
+ opcodes_sorted = 1;
+ }
+
+memcpy(&insn,buffer, sizeof (insn));
+
+ for (i = 0; i < NUMOPCODES; ++i)
+ {
+ const struct sparc_opcode *opcode = &sparc_opcodes[i];
+ if ((opcode->match & insn.code) == opcode->match
+ && (opcode->lose & insn.code) == 0)
+ {
+ /* Nonzero means that we have found an instruction which has
+ the effect of adding or or'ing the imm13 field to rs1. */
+ int imm_added_to_rs1 = 0;
+
+ /* Nonzero means that we have found a plus sign in the args
+ field of the opcode table. */
+ int found_plus = 0;
+
+ /* Do we have an 'or' instruction where rs1 is the same
+ as rsd, and which has the i bit set? */
+ if (opcode->match == 0x80102000
+ && insn.rs1 == insn.rd)
+ imm_added_to_rs1 = 1;
+
+ if (index (opcode->args, 'S') != 0)
+ /* Reject the special case for `set'.
+ The real `sethi' will match. */
+ continue;
+ if (insn.rs1 != insn.rd
+ && index (opcode->args, 'r') != 0)
+ /* Can't do simple format if source and dest are different. */
+ continue;
+
+ fputs (opcode->name, stream);
+
+ {
+ register const char *s;
+
+ if (opcode->args[0] != ',')
+ fputs (" ", stream);
+ for (s = opcode->args; *s != '\0'; ++s)
+ {
+ if (*s == ',')
+ {
+ fputs (",", stream);
+ ++s;
+ if (*s == 'a')
+ {
+ fputs ("a", stream);
+ ++s;
+ }
+ fputs (" ", stream);
+ }
+
+ switch (*s)
+ {
+ case '+':
+ found_plus = 1;
+
+ /* note fall-through */
+ default:
+ fprintf (stream, "%c", *s);
+ break;
+
+ case '#':
+ fputs ("0", stream);
+ break;
+
+#define reg(n) fprintf (stream, "%%%s", reg_names[n])
+ case '1':
+ case 'r':
+ reg (insn.rs1);
+ break;
+
+ case '2':
+ reg (insn.rs2);
+ break;
+
+ case 'd':
+ reg (insn.rd);
+ break;
+#undef reg
+
+#define freg(n) fprintf (stream, "%%%s", freg_names[n])
+ case 'e':
+ freg (insn.rs1);
+ break;
+
+ case 'f':
+ freg (insn.rs2);
+ break;
+
+ case 'g':
+ freg (insn.rd);
+ break;
+#undef freg
+
+#define creg(n) fprintf (stream, "%%c%u", (unsigned int) (n))
+ case 'b':
+ creg (insn.rs1);
+ break;
+
+ case 'c':
+ creg (insn.rs2);
+ break;
+
+ case 'D':
+ creg (insn.rd);
+ break;
+#undef creg
+
+ case 'h':
+ fprintf (stream, "%%hi(%#x)",
+ (unsigned int) insn.imm22 << 10);
+ break;
+
+ case 'i':
+ {
+ /* We cannot trust the compiler to sign-extend
+ when extracting the bitfield, hence the shifts. */
+ int imm = ((int) insn.imm13 << 19) >> 19;
+
+ /* Check to see whether we have a 1+i, and take
+ note of that fact.
+
+ Note: because of the way we sort the table,
+ we will be matching 1+i rather than i+1,
+ so it is OK to assume that i is after +,
+ not before it. */
+ if (found_plus)
+ imm_added_to_rs1 = 1;
+
+ if (imm <= 9)
+ fprintf (stream, "%d", imm);
+ else
+ fprintf (stream, "%#x", (unsigned) imm);
+ }
+ break;
+
+ case 'L':
+ print_address ((bfd_vma) memaddr + insn.disp30 * 4,
+ stream);
+ break;
+
+ case 'l':
+ if ((insn.code >> 22) == 0)
+ /* Special case for `unimp'. Don't try to turn
+ it's operand into a function offset. */
+ fprintf (stream, "%#x",
+ (unsigned) (((int) insn.disp22 << 10) >> 10));
+ else
+ /* We cannot trust the compiler to sign-extend
+ when extracting the bitfield, hence the shifts. */
+ print_address ((bfd_vma)
+ (memaddr
+ + (((int) insn.disp22 << 10) >> 10) * 4),
+ stream);
+ break;
+
+ case 'A':
+ fprintf (stream, "(%d)", (int) insn.asi);
+ break;
+
+ case 'C':
+ fputs ("%csr", stream);
+ break;
+
+ case 'F':
+ fputs ("%fsr", stream);
+ break;
+
+ case 'p':
+ fputs ("%psr", stream);
+ break;
+
+ case 'q':
+ fputs ("%fq", stream);
+ break;
+
+ case 'Q':
+ fputs ("%cq", stream);
+ break;
+
+ case 't':
+ fputs ("%tbr", stream);
+ break;
+
+ case 'w':
+ fputs ("%wim", stream);
+ break;
+
+ case 'y':
+ fputs ("%y", stream);
+ break;
+ }
+ }
+ }
+
+ /* If we are adding or or'ing something to rs1, then
+ check to see whether the previous instruction was
+ a sethi to the same register as in the sethi.
+ If so, attempt to print the result of the add or
+ or (in this context add and or do the same thing)
+ and its symbolic value. */
+ if (imm_added_to_rs1)
+ {
+ union sparc_insn prev_insn;
+ int errcode;
+
+ memcpy(&prev_insn, buffer -4, sizeof (prev_insn));
+
+ if (errcode == 0)
+ {
+ /* If it is a delayed branch, we need to look at the
+ instruction before the delayed branch. This handles
+ sequences such as
+
+ sethi %o1, %hi(_foo), %o1
+ call _printf
+ or %o1, %lo(_foo), %o1
+ */
+
+ if (is_delayed_branch (prev_insn))
+ memcpy(&prev_insn, buffer - 8, sizeof(prev_insn));
+
+ }
+
+ /* If there was a problem reading memory, then assume
+ the previous instruction was not sethi. */
+ if (errcode == 0)
+ {
+ /* Is it sethi to the same register? */
+ if ((prev_insn.code & 0xc1c00000) == 0x01000000
+ && prev_insn.rd == insn.rs1)
+ {
+ fprintf (stream, "\t! ");
+ /* We cannot trust the compiler to sign-extend
+ when extracting the bitfield, hence the shifts. */
+ print_address (((int) prev_insn.imm22 << 10)
+ | (insn.imm13 << 19) >> 19, stream);
+ }
+ }
+ }
+
+ return sizeof (insn);
+ }
+ }
+
+ fprintf ("%#8x", insn.code);
+ return sizeof (insn);
+}
+
+
+/* Compare opcodes A and B. */
+
+static int
+compare_opcodes (a, b)
+ char *a, *b;
+{
+ struct sparc_opcode *op0 = (struct sparc_opcode *) a;
+ struct sparc_opcode *op1 = (struct sparc_opcode *) b;
+ unsigned long int match0 = op0->match, match1 = op1->match;
+ unsigned long int lose0 = op0->lose, lose1 = op1->lose;
+ register unsigned int i;
+
+ /* If a bit is set in both match and lose, there is something
+ wrong with the opcode table. */
+ if (match0 & lose0)
+ {
+ fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+ op0->name, match0, lose0);
+ op0->lose &= ~op0->match;
+ lose0 = op0->lose;
+ }
+
+ if (match1 & lose1)
+ {
+ fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
+ op1->name, match1, lose1);
+ op1->lose &= ~op1->match;
+ lose1 = op1->lose;
+ }
+
+ /* Because the bits that are variable in one opcode are constant in
+ another, it is important to order the opcodes in the right order. */
+ for (i = 0; i < 32; ++i)
+ {
+ unsigned long int x = 1 << i;
+ int x0 = (match0 & x) != 0;
+ int x1 = (match1 & x) != 0;
+
+ if (x0 != x1)
+ return x1 - x0;
+ }
+
+ for (i = 0; i < 32; ++i)
+ {
+ unsigned long int x = 1 << i;
+ int x0 = (lose0 & x) != 0;
+ int x1 = (lose1 & x) != 0;
+
+ if (x0 != x1)
+ return x1 - x0;
+ }
+
+ /* They are functionally equal. So as long as the opcode table is
+ valid, we can put whichever one first we want, on aesthetic grounds. */
+ {
+ int length_diff = strlen (op0->args) - strlen (op1->args);
+ if (length_diff != 0)
+ /* Put the one with fewer arguments first. */
+ return length_diff;
+ }
+
+ /* Put 1+i before i+1. */
+ {
+ char *p0 = (char *) index(op0->args, '+');
+ char *p1 = (char *) index(op1->args, '+');
+
+ if (p0 && p1)
+ {
+ /* There is a plus in both operands. Note that a plus
+ sign cannot be the first character in args,
+ so the following [-1]'s are valid. */
+ if (p0[-1] == 'i' && p1[1] == 'i')
+ /* op0 is i+1 and op1 is 1+i, so op1 goes first. */
+ return 1;
+ if (p0[1] == 'i' && p1[-1] == 'i')
+ /* op0 is 1+i and op1 is i+1, so op0 goes first. */
+ return -1;
+ }
+ }
+
+ /* They are, as far as we can tell, identical.
+ Since qsort may have rearranged the table partially, there is
+ no way to tell which one was first in the opcode table as
+ written, so just say there are equal. */
+ return 0;
+}
diff --git a/binutils/version.c b/binutils/version.c
new file mode 100644
index 0000000..d3e5a132
--- /dev/null
+++ b/binutils/version.c
@@ -0,0 +1,5 @@
+/*** version.c -- version number for binutils.
+ They all change in lockstep -- it's easier that way
+*/
+
+char *program_version = "1.10 (Cygnus BFD)";