Imported Upstream version 3.2.2
[debian/gnuradio] / gcell / lib / runtime / gc_proc_def_utils.cc
diff --git a/gcell/lib/runtime/gc_proc_def_utils.cc b/gcell/lib/runtime/gc_proc_def_utils.cc
new file mode 100644 (file)
index 0000000..0250d67
--- /dev/null
@@ -0,0 +1,123 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008 Free Software Foundation, Inc.
+ * 
+ * This file is part of GNU Radio
+ * 
+ * GNU Radio 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gc_proc_def_utils.h>
+#include <gcell/gc_declare_proc.h>
+#include <elf.h>
+#include <stdio.h>
+#include <string.h>
+
+static const unsigned char expected[EI_PAD] = {
+  ELFMAG0,
+  ELFMAG1,
+  ELFMAG2,
+  ELFMAG3,
+  ELFCLASS32,
+  ELFDATA2MSB,
+  EV_CURRENT,
+  ELFOSABI_SYSV,
+  0
+};
+
+
+/*
+ * Basically we're going to find the GC_PROC_DEF_SECTION section
+ * in the ELF file and return a pointer to it.  The only things in that
+ * section are gc_proc_def's
+ */
+bool 
+gcpd_find_table(spe_program_handle_t *handle,
+               struct gc_proc_def **table, int *nentries, uint32_t *ls_addr)
+{
+  if (!handle || !table || !nentries)
+    return false;
+
+  *table = 0;
+  *nentries = 0;
+  
+  Elf32_Ehdr *ehdr = (Elf32_Ehdr *)handle->elf_image;
+  if (!ehdr){
+    fprintf(stderr, "gcpd: No ELF image has been loaded\n");
+    return false;
+  }
+
+  // quick check that we're looking at a SPE EXEC object
+
+  if (memcmp(ehdr->e_ident, expected, EI_PAD) != 0){
+    fprintf(stderr, "gcpd: invalid ELF header\n");
+    return false;
+  }
+
+  if (ehdr->e_machine != 0x17){                // confirm machine type (EM_SPU)
+    fprintf(stderr, "gcpd: not an SPE ELF object\n");
+    return false;
+  }
+
+  if (ehdr->e_type != ET_EXEC){
+    fprintf(stderr, "gcpd: invalid SPE ELF type.\n");
+    fprintf(stderr, "gcpd: SPE type %d != %d\n", ehdr->e_type, ET_EXEC);
+    return false;
+  }
+
+  // find the section header table
+
+  Elf32_Shdr *shdr;
+  Elf32_Shdr *sh;
+
+  if (ehdr->e_shentsize != sizeof (*shdr)){
+    fprintf(stderr, "gcpd: invalid section header format.\n");
+    return false;
+  }
+
+  if (ehdr->e_shnum == 0){
+    fprintf(stderr, "gcpd: no section headers in file.\n");
+    return false;
+  }
+
+  shdr = (Elf32_Shdr *) ((char *)ehdr + ehdr->e_shoff);
+  char *str_table = (char *)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
+
+  // traverse the sections looking for GC_PROC_DEF_SECTION
+  
+  for (sh = shdr; sh < &shdr[ehdr->e_shnum]; sh++){
+    if (0){
+      fprintf(stderr, "section name: %s (start: 0x%04x, size: 0x%04x)\n",
+             str_table + sh->sh_name, sh->sh_offset, sh->sh_size);
+    }
+
+    if (strcmp(GC_PROC_DEF_SECTION, str_table+sh->sh_name) == 0){
+      *table = (struct gc_proc_def *)((char *)ehdr + sh->sh_offset);
+      if (sh->sh_size % (sizeof(struct gc_proc_def)) != 0){
+       fprintf(stderr, "gcpd: %s section has invalid format\n", GC_PROC_DEF_SECTION);
+       return false;
+      }
+      *nentries = sh->sh_size / sizeof(struct gc_proc_def);
+      *ls_addr = sh->sh_addr;
+      return true;
+    }
+  }
+
+  return false;
+}