Example #1
0
bool
rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
{
  int fd;

  if (!rtems_rtl_obj_fname_valid (obj))
  {
    rtems_rtl_set_error (ENOMEM, "invalid object file name path");
    return false;
  }

  fd = open (rtems_rtl_obj_fname (obj), O_RDONLY);
  if (fd < 0)
  {
    rtems_rtl_set_error (ENOMEM, "opening for object file");
    return false;
  }

  /*
   * Find the object file in the archive if it is an archive that
   * has been opened.
   */
  if (rtems_rtl_obj_aname_valid (obj))
  {
    if (!rtems_rtl_obj_archive_find (obj, fd))
    {
      rtems_rtl_obj_caches_flush ();
      close (fd);
      return false;
    }
  }

  /*
   * Call the format specific loader. Currently this is a call to the ELF
   * loader. This call could be changed to allow probes then calls if more than
   * one format is supported.
   */
  if (!rtems_rtl_obj_file_load (obj, fd))
  {
    rtems_rtl_obj_caches_flush ();
    close (fd);
    return false;
  }

  if (!_rtld_linkmap_add (obj)) /* For GDB */
  {
    close (fd);
    return false;
  }

  rtems_rtl_obj_caches_flush ();

  close (fd);

  return true;
}
Example #2
0
bool
rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
                           int              section,
                           const char*      name,
                           size_t           size,
                           off_t            offset,
                           uint32_t         alignment,
                           int              link,
                           int              info,
                           uint32_t         flags)
{
  rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
                                                    sizeof (rtems_rtl_obj_sect_t), true);
  if (!sect)
  {
    rtems_rtl_set_error (ENOMEM, "adding allocated section");
    return false;
  }
  sect->section = section;
  sect->name = rtems_rtl_strdup (name);
  sect->size = size;
  sect->offset = offset;
  sect->alignment = alignment;
  sect->link = link;
  sect->info = info;
  sect->flags = flags;
  sect->base = NULL;
  rtems_chain_append (&obj->sections, &sect->node);

  if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
    printf ("rtl: sect: %-2d: %s\n", section, name);

  return true;
}
Example #3
0
static size_t
rtems_rtl_obj_sections_loader (uint32_t                     mask,
                               rtems_rtl_obj_t*             obj,
                               int                          fd,
                               uint8_t*                     base,
                               rtems_rtl_obj_sect_handler_t handler,
                               void*                        data)
{
  rtems_chain_control* sections = &obj->sections;
  rtems_chain_node*    node = rtems_chain_first (sections);
  size_t               base_offset = 0;
  bool                 first = true;
  while (!rtems_chain_is_tail (sections, node))
  {
    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;

    if ((sect->size != 0) && ((sect->flags & mask) != 0))
    {
      if (!first)
        base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);

      sect->base = base + base_offset;

      if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
        printf ("rtl: loading: %s -> %8p (%zi)\n",
                sect->name, sect->base, sect->size);

      if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
      {
        if (!handler (obj, fd, sect, data))
        {
          sect->base = 0;
          return false;
        }
      }
      else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
      {
        memset (base + base_offset, 0, sect->size);
      }
      else
      {
        sect->base = 0;
        rtems_rtl_set_error (errno, "section has no load op");
        return false;
      }

      base_offset += sect->size;
      first = false;
    }

    node = rtems_chain_next (node);
  }

  return true;
}
Example #4
0
bool
rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t*      obj,
                             const Elf_Rela*             rela,
                             const rtems_rtl_obj_sect_t* sect,
                             const char*                 symname,
                             const Elf_Byte              syminfo,
                             const Elf_Word              symvalue)
{
  rtems_rtl_set_error (EINVAL, "rela type record not supported");
  return false;
}
Example #5
0
bool
rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
{
  int l;

  for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l)
  {
    if (loaders[l].check (obj, fd))
      return loaders[l].load (obj, fd);
  }

  rtems_rtl_set_error (ENOENT, "no format loader found");
  return false;
}
Example #6
0
bool
rtems_rtl_obj_cache_open (rtems_rtl_obj_cache_t* cache, size_t size)
{
  cache->fd        = -1;
  cache->file_size = 0;
  cache->offset    = 0;
  cache->size      = size;
  cache->level     = 0;
  cache->buffer    = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false);
  if (!cache->buffer)
  {
    rtems_rtl_set_error (ENOMEM, "no memory for cache buffer");
    return false;
  }
  return true;
}
Example #7
0
static rtems_rtl_unresolv_block_t*
rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved_t* unresolved)
{
    /*
     * The block header contains a record.
     */
    size_t size =
        (sizeof(rtems_rtl_unresolv_block_t) +
         (sizeof(rtems_rtl_unresolv_rec_t) * (unresolved->block_recs - 1)));
    rtems_rtl_unresolv_block_t* block =
        rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
    if (block)
        rtems_chain_append (&unresolved->blocks, &block->link);
    else
        rtems_rtl_set_error (ENOMEM, "no memory for unresolved block");
    return block;
}
Example #8
0
bool
rtems_rtl_symbol_table_open (rtems_rtl_symbols_t* symbols,
                             size_t               buckets)
{
  symbols->buckets = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
                                          buckets * sizeof (rtems_chain_control),
                                          true);
  if (!symbols->buckets)
  {
    rtems_rtl_set_error (ENOMEM, "no memory for global symbol table");
    return false;
  }
  symbols->nbuckets = buckets;
  for (buckets = 0; buckets < symbols->nbuckets; ++buckets)
    rtems_chain_initialize_empty (&symbols->buckets[buckets]);
  rtems_rtl_symbol_global_insert (symbols, &global_sym_add);
  return true;
}
Example #9
0
bool
rtems_rtl_obj_comp_open (rtems_rtl_obj_comp_t*  comp,
                         size_t                 size)
{
  comp->cache  = NULL;
  comp->fd = -1;
  comp->compression = RTEMS_RTL_COMP_LZ77;
  comp->offset = 0;
  comp->size   = size;
  comp->level  = 0;
  comp->buffer = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false);
  if (!comp->buffer)
  {
    rtems_rtl_set_error (ENOMEM, "no memory for compressor buffer");
    return false;
  }
  comp->read = 0;
  return true;
}
Example #10
0
bool
rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
{
  if (obj->users || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0))
  {
    rtems_rtl_set_error (EINVAL, "cannot free obj still in use");
    return false;
  }
  if (!rtems_chain_is_node_off_chain (&obj->link))
    rtems_chain_extract (&obj->link);
  rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
                              &obj->data_base, &obj->bss_base);
  rtems_rtl_symbol_obj_erase (obj);
  rtems_rtl_obj_free_names (obj);
  if (obj->sec_num)
    free (obj->sec_num);
  if (obj->detail)
    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*)obj->detail);
  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
  return true;
}
Example #11
0
bool
rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name)
{
  const char*       pname;
  rtems_rtl_data_t* rtl;

  /*
   * Parse the name. The object descriptor will have the archive name and/or
   * object name fields filled in. A find of the file will result in the file
   * name (fname) field pointing to the actual file if present on the file
   * system.
   */
  if (!rtems_rtl_obj_parse_name (obj, name))
    return false;

  /*
   * If the archive field (aname) is set we use that name else we use the
   * object field (oname). If selected name is absolute we just point the aname
   * field to the fname field to that name. If the field is relative we search
   * the paths set in the RTL for the file.
   */
  if (rtems_rtl_obj_aname_valid (obj))
    pname = rtems_rtl_obj_aname (obj);
  else
    pname = rtems_rtl_obj_oname (obj);

  rtl = rtems_rtl_lock ();

  if (!rtems_rtl_find_file (pname, rtl->paths, &obj->fname, &obj->fsize))
  {
    rtems_rtl_set_error (ENOENT, "file not found");
    rtems_rtl_unlock ();
    return false;
  }

  rtems_rtl_unlock ();

  return true;
}
Example #12
0
bool
rtems_rtl_find_file (const char*  name,
                     const char*  paths,
                     const char** file_name,
                     size_t*      size)
{
  struct stat sb;

  *file_name = NULL;
  *size = 0;

  if (rtems_filesystem_is_delimiter (name[0]) || (name[0] == '.'))
  {
    if (stat (name, &sb) == 0)
      *file_name = rtems_rtl_strdup (name);
  }
  else if (paths)
  {
    const char* start;
    const char* end;
    int         len;
    char*       fname;

    start = paths;
    end = start + strlen (paths);
    len = strlen (name);

    while (!*file_name && (start != end))
    {
      const char* delimiter = strchr (start, ':');

      if (delimiter == NULL)
        delimiter = end;

      /*
       * Allocate the path fragment, separator, name, terminating nul. Form the
       * path then see if the stat call works.
       */

      fname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
                                   (delimiter - start) + 1 + len + 1, true);
      if (!fname)
      {
        rtems_rtl_set_error (ENOMEM, "no memory searching for file");
        return false;
      }

      memcpy (fname, start, delimiter - start);
      fname[delimiter - start] = '/';
      memcpy (fname + (delimiter - start) + 1, name, len);

      if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD))
        printf ("rtl: find-file: path: %s\n", fname);

      if (stat (fname, &sb) < 0)
        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, fname);
      else
        *file_name = fname;

      start = delimiter;
      if (start != end)
        ++start;
    }
  }

  if (!*file_name)
    return false;

  *size = sb.st_size;

  return true;
}
Example #13
0
bool
rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t*      obj,
                             const Elf_Rela*             rela,
                             const rtems_rtl_obj_sect_t* sect,
                             const char*                 symname,
                             const Elf_Byte              syminfo,
                             const Elf_Word              symvalue)
{
  Elf_Addr* where;
  Elf_Word tmp;
  uint32_t mask = 0;
  uint32_t bits = 0;

  where = (Elf_Addr *)(sect->base + rela->r_offset);
  switch (ELF_R_TYPE(rela->r_info)) {
    case R_TYPE(NONE):
      break;

    case R_TYPE(32):
      /*
       * value:1; Field: word32; Expression: S + A
       */
      *where = symvalue + rela->r_addend;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: ADDR32 %p @ %p in %s\n",
                (void *)*(where), where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(14):
      /*
       * value:7; Field: low14*; Expression: (S + A) >> 2
       */
    case R_TYPE(24):
      /*
       * value:2; Field: low24*; Expression: (S + A) >> 2
       */
      if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) {
        bits = 14;
        mask = 0xfffc;
      } else {
        bits = 24;
        mask = 0x3fffffc;
      }
      tmp = (symvalue + rela->r_addend) >> 2;
      if (tmp > ((1<<bits) - 1 )) {
        printf("Overflow ADDR14/ADDR24\n");
        return false;
      }
      tmp = *where;
      tmp &= ~mask;
      tmp |= (symvalue + rela->r_addend) & mask;
      *where = tmp;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n",
                (void *)*where, where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(16_HA):
      /*
       * value:6; Field:half16; Expression: #ha(S+A)
       */

      tmp = symvalue + rela->r_addend;
      *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff);
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: 16_HA %p @ %p in %s\n",
                (void *)*(where), where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(16_HI):
      /*
       * value:5; Field:half16; Expression: #hi(S+A)
       */
      *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: 16_HI %p @ %p in %s\n",
                (void *)*where, where, rtems_rtl_obj_oname (obj));
      break;
    case R_TYPE(16_LO):
      /*
       * value:4; Field:half16; Expression: #lo(S+A)
       */
      *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: 16_LO %p @ %p in %s\n",
                (void *)*where, where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(REL14):
      /*
       * value:11; Field:low14*; Expression:(S+A-P)>>2
       */
    case R_TYPE(REL24):
      /*
       * value:10; Field:low24*; Expression:(S+A-P)>>2
       */
      if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) {
        mask = 0x3fffffc;
        bits = 24;
      }
      else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) {
        mask = 0xfffc;
        bits = 14;
      }

      tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
      if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
          ((Elf_Sword)tmp < -(1<<(bits-1)))) {
        printf("Overflow REL14/REL24\n");
        return false;
      }

      tmp = *where;
      tmp &= ~mask;
      tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
      *where = tmp;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: REL24/REL14 %p @ %p in %s\n",
                (void *)*where, where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(REL32):
      /*
       * value:26; Field:word32*; Expression:S+A-P
       */
      *where = symvalue + rela->r_addend - (Elf_Addr)where;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: REL32 %p @ %p in %s\n",
                (void *)*where, where, rtems_rtl_obj_oname (obj));
      break;

    default:
      printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
              "contents = %p\n",
              ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
              (void *)rela->r_offset, (void *)*where);
      rtems_rtl_set_error (EINVAL,
                           "%s: Unsupported relocation type %ld "
                           "in non-PLT relocations",
                           sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
      return false;
  }
  return true;
}
Example #14
0
bool
rtems_rtl_symbol_global_add (rtems_rtl_obj_t*     obj,
                             const unsigned char* esyms,
                             unsigned int         size)
{
  rtems_rtl_symbols_t* symbols;
  rtems_rtl_obj_sym_t* sym;
  size_t               count;
  size_t               s;
  uint32_t             marker;

  count = 0;
  s = 0;
  while ((s < size) && (esyms[s] != 0))
  {
    int l = strlen ((char*) &esyms[s]);
    if ((esyms[s + l] != '\0') || ((s + l) > size))
    {
      rtems_rtl_set_error (EINVAL, "invalid exported symbol table");
      return false;
    }
    ++count;
    s += l + sizeof (unsigned long) + 1;
  }

  /*
   * Check this is the correct end of the table.
   */
  marker = esyms[s + 1];
  marker <<= 8;
  marker |= esyms[s + 2];
  marker <<= 8;
  marker |= esyms[s + 3];
  marker <<= 8;
  marker |= esyms[s + 4];

  if (marker != 0xdeadbeefUL)
  {
    rtems_rtl_set_error (ENOMEM, "invalid export symbol table");
    return false;
  }

  if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
    printf ("rtl: global symbol add: %zi\n", count);

  obj->global_size = count * sizeof (rtems_rtl_obj_sym_t);
  obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
                                           obj->global_size, true);
  if (!obj->global_table)
  {
    obj->global_size = 0;
    rtems_rtl_set_error (ENOMEM, "no memory for global symbols");
    return false;
  }

  symbols = rtems_rtl_global_symbols ();

  s = 0;
  sym = obj->global_table;

  while ((s < size) && (esyms[s] != 0))
  {
    /*
     * Copy the void* using a union and memcpy to avoid any strict aliasing or
     * alignment issues. The variable length of the label and the packed nature
     * of the table means casting is not suitable.
     */
    union {
      uint8_t data[sizeof (void*)];
      void*   value;
    } copy_voidp;
    int b;

    sym->name = (const char*) &esyms[s];
    s += strlen (sym->name) + 1;
    for (b = 0; b < sizeof (void*); ++b, ++s)
      copy_voidp.data[b] = esyms[s];
    sym->value = copy_voidp.value;
    if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM))
      printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value);
    if (rtems_rtl_symbol_global_find (sym->name) == NULL)
      rtems_rtl_symbol_global_insert (symbols, sym);
    ++sym;
  }

  obj->global_syms = count;

  return true;
}
Example #15
0
bool
rtems_rtl_obj_comp_read (rtems_rtl_obj_comp_t* comp,
                         void*                 buffer,
                         size_t                length)
{
  uint8_t* bin = buffer;

  if (!comp->cache)
  {
    rtems_rtl_set_error (EINVAL, "not open");
    return false;
  }

  if (comp->fd != comp->cache->fd)
  {
    comp->level = 0;
  }

  while (length)
  {
    size_t buffer_level;

    buffer_level = length > comp->level ? comp->level : length;

    if (buffer_level)
    {
      memcpy (bin, comp->buffer, buffer_level);

      if ((comp->level - buffer_level) != 0)
      {
        memmove (comp->buffer,
                 comp->buffer + buffer_level,
                 comp->level - buffer_level);
      }

      bin += buffer_level;
      length -= buffer_level;
      comp->level -= buffer_level;
      comp->read += buffer_level;
    }

    if (length)
    {
      uint8_t* input = NULL;
      uint16_t block_size;
      size_t   in_length = sizeof (block_size);
      int      decompressed;

      if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset,
                                     (void**) &input, &in_length))
        return false;

      block_size = (input[0] << 8) | input[1];

      comp->offset += sizeof (block_size);

      in_length = block_size;

      if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset,
                                     (void**) &input, &in_length))
        return false;

      if (in_length != block_size)
      {
        rtems_rtl_set_error (EIO, "compressed read failed: bs=%u in=%u",
                             block_size, in_length);
        return false;
      }

      switch (comp->compression)
      {
        case RTEMS_RTL_COMP_NONE:
          memcpy (comp->buffer, input, in_length);
          decompressed = in_length;
          break;

        case RTEMS_RTL_COMP_LZ77:
          decompressed = fastlz_decompress (input, in_length,
                                            comp->buffer, comp->size);
          if (decompressed == 0)
          {
            rtems_rtl_set_error (EBADF, "decompression failed");
            return false;
          }
          break;

        default:
          rtems_rtl_set_error (EINVAL, "bad compression type");
          return false;
      }

      comp->offset += block_size;

      comp->level = decompressed;
    }
  }

  return true;
}
Example #16
0
bool
rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
                            const Elf_Rel*              rel,
                            const rtems_rtl_obj_sect_t* sect,
                            const char*                 symname,
                            const Elf_Byte              syminfo,
                            const Elf_Word              symvalue)
{
	Elf_Addr  target = 0;
  Elf_Addr* where;
  Elf_Addr  tmp;

  where = (Elf_Addr *)(sect->base + rel->r_offset);

  switch (ELF_R_TYPE(rel->r_info)) {
    case R_TYPE(NONE):
      break;

    case R_TYPE(PC32):
      target = (Elf_Addr) symvalue;
      *where += target - (Elf_Addr)where;

      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: reloc PC32 in %s --> %p (%p @ %p) in %s\n",
                sect->name, (void*) symvalue,
                (void *)*where, where, rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(GOT32):
    case R_TYPE(32):
    case R_TYPE(GLOB_DAT):
      target = (Elf_Addr) symvalue;

      tmp = target + *where;
      if (*where != tmp)
        *where = tmp;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: reloc 32/GLOB_DAT in %s --> %p @ %p in %s\n",
                sect->name, (void *)*where, where,
                rtems_rtl_obj_oname (obj));
      break;

    case R_TYPE(RELATIVE):
      *where += (Elf_Addr)sect->base;
      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
        printf ("rtl: reloc RELATIVE in %s --> %p @ %p\n",
                rtems_rtl_obj_oname (obj), (void *)*where, where);
      break;

    case R_TYPE(COPY):
      printf ("rtl: reloc COPY (please report)\n");
      break;

    default:
      printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
              "contents = %p\n",
              ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
              (void *)rel->r_offset, (void *)*where);
      rtems_rtl_set_error (EINVAL,
                           "%s: Unsupported relocation type %ld "
                           "in non-PLT relocations",
                           sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
      return false;
  }

  return true;
}
Example #17
0
bool
rtems_rtl_obj_cache_read (rtems_rtl_obj_cache_t* cache,
                          int                    fd,
                          off_t                  offset,
                          void**                 buffer,
                          size_t*                length)
{
  struct stat sb;

  if (*length > cache->size)
  {
    rtems_rtl_set_error (EINVAL, "read size larger than cache size");
    return false;
  }

  if (cache->fd == fd)
  {
    if (offset > cache->file_size)
    {
      rtems_rtl_set_error (EINVAL, "offset past end of file: offset=%i size=%i",
                           (int) offset, (int) cache->file_size);
      return false;
    }

    if ((offset + *length) > cache->file_size)
      *length = cache->file_size - offset;
  }

  while (true)
  {
    size_t buffer_offset = 0;
    size_t buffer_read = cache->size;

    /*
     * Is the data in the cache for this file ?
     */
    if (fd == cache->fd)
    {
      /*
       * Is any part of the data in the cache ?
       */
      if ((offset >= cache->offset) &&
          (offset < (cache->offset + cache->level)))
      {
        buffer_offset = offset - cache->offset;

        /*
         * Return the location of the data in the cache.
         */
        *buffer = cache->buffer + buffer_offset;

        /*
         * Is all the data in the cache or just a part ?
         */
        if (*length <= (cache->level - buffer_offset))
        {
          return true;
        }

        /*
         * Copy down the data in the buffer and then fill the remaining
         * space with as much data we are able to read.
         */
        memmove (cache->buffer,
                 cache->buffer + buffer_offset,
                 cache->size - buffer_offset);

        buffer_read   = buffer_offset;
        buffer_offset = cache->size - buffer_offset;
      }
    }

    if (lseek (fd, offset + buffer_offset, SEEK_SET) < 0)
    {
      rtems_rtl_set_error (errno, "file seek failed");
      return false;
    }

    /*
     * Loop reading the data from the file until either an error or 0 is
     * returned and if data has been read check if the amount is what we
     * want. If not it is an error. A POSIX read can read data in fragments.
     */
    cache->level = buffer_read;
    while (buffer_read)
    {
      int r = read (fd, cache->buffer + buffer_offset, buffer_read);
      if (r < 0)
      {
        rtems_rtl_set_error (errno, "file read failed");
        return false;
      }
      if ((r == 0) && buffer_read)
      {
        cache->level = cache->level - buffer_read;
        buffer_read = 0;
      }
      else
      {
        buffer_read -= r;
        buffer_offset += r;
      }
    }

    cache->fd = fd;
    cache->offset = offset;

    if (fstat (cache->fd, &sb) < 0)
    {
      rtems_rtl_set_error (errno, "file stat failed");
      return false;
    }

    cache->file_size = sb.st_size;
  }

  return false;
}
Example #18
0
/**
 * Find a module in an archive returning the offset in the archive in the
 * object descriptor.
 */
static bool
rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
{
#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
#define RTEMS_RTL_AR_FNAME      (0)
#define RTEMS_RTL_AR_FNAME_SIZE (16)
#define RTEMS_RTL_AR_SIZE       (48)
#define RTEMS_RTL_AR_SIZE_SIZE  (10)
#define RTEMS_RTL_AR_MAGIC      (58)
#define RTEMS_RTL_AR_MAGIC_SIZE (2)
#define RTEMS_RTL_AR_FHDR_SIZE  (60)

  size_t  fsize = obj->fsize;
  off_t   extended_file_names;
  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
  bool    scanning;

  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
  {
    rtems_rtl_set_error (errno, "reading archive identifer");
    return false;
  }

  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
  {
    rtems_rtl_set_error (EINVAL, "invalid archive identifer");
    return false;
  }

  /*
   * Seek to the current offset in the archive and if we have a valid archive
   * file header present check the file name for a match with the oname field
   * of the object descriptor. If the archive header is not valid and it is the
   * first pass reset the offset and start the search again in case the offset
   * provided is not valid any more.
   *
   * The archive can have a symbol table at the start. Ignore it. A symbol
   * table has the file name '/'.
   *
   * The archive can also have the GNU extended file name table. This
   * complicates the processing. If the object's file name starts with '/' the
   * remainder of the file name is an offset into the extended file name
   * table. To find the extended file name table we need to scan from start of
   * the archive for a file name of '//'. Once found we remeber the table's
   * start and can direct seek to file name location. In other words the scan
   * only happens once.
   *
   * If the name had the offset encoded we go straight to that location.
   */

  if (obj->ooffset != 0)
    scanning = false;
  else
  {
    scanning = true;
    obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
  }

  extended_file_names = 0;

  while (obj->ooffset < fsize)
  {
    /*
     * Clean up any existing data.
     */
    memset (header, 0, sizeof (header));

    if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
    {
      rtems_rtl_set_error (errno, "seek/read archive file header");
      obj->ooffset = 0;
      obj->fsize = 0;
      return false;
    }

    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
    {
      if (scanning)
      {
        rtems_rtl_set_error (EINVAL, "invalid archive file header");
        obj->ooffset = 0;
        obj->fsize = 0;
        return false;
      }

      scanning = true;
      obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
      continue;
    }

    /*
     * The archive header is always aligned to an even address.
     */
    obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
                                          RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;

    /*
     * Check for the GNU extensions.
     */
    if (header[0] == '/')
    {
      off_t extended_off;

      switch (header[1])
      {
        case ' ':
          /*
           * Symbols table. Ignore the table.
           */
          break;
        case '/':
          /*
           * Extended file names table. Remember.
           */
          extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE;
          break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          /*
           * Offset into the extended file name table. If we do not have the
           * offset to the extended file name table find it.
           */
          extended_off =
            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);

          if (extended_file_names == 0)
          {
            off_t off = obj->ooffset;
            while (extended_file_names == 0)
            {
              off_t esize =
                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
              off += esize + RTEMS_RTL_AR_FHDR_SIZE;

              if (!rtems_rtl_seek_read (fd, off,
                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
              {
                rtems_rtl_set_error (errno,
                                     "seeking/reading archive ext file name header");
                obj->ooffset = 0;
                obj->fsize = 0;
                return false;
              }

              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
              {
                rtems_rtl_set_error (errno, "invalid archive file header");
                obj->ooffset = 0;
                obj->fsize = 0;
                return false;
              }

              if ((header[0] == '/') && (header[1] == '/'))
              {
                extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
                break;
              }
            }
          }

          if (extended_file_names)
          {
            /*
             * We know the offset in the archive to the extended file. Read the
             * name from the table and compare with the name we are after.
             */
#define RTEMS_RTL_MAX_FILE_SIZE (256)
            char  name[RTEMS_RTL_MAX_FILE_SIZE];

            if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
            {
              rtems_rtl_set_error (errno,
                                   "invalid archive ext file seek/read");
              obj->ooffset = 0;
              obj->fsize = 0;
              return false;
            }

            if (rtems_rtl_match_name (obj, name))
            {
              obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
              return true;
            }
          }
          break;
        default:
          /*
           * Ignore the file because we do not know what it it.
           */
          break;
      }
    }
    else
    {
      if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME]))
      {
        obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
        return true;
      }
    }

    obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE;
  }

  rtems_rtl_set_error (ENOENT, "object file not found");
  obj->ooffset = 0;
  obj->fsize = 0;
  return false;
}
Example #19
0
bool
rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             obj,
                             int                          fd,
                             rtems_rtl_obj_sect_handler_t handler,
                             void*                        data)
{
  size_t text_size;
  size_t const_size;
  size_t data_size;
  size_t bss_size;

  text_size  = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
  const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj);
  data_size  = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
  bss_size   = rtems_rtl_obj_bss_size (obj);

  /*
   * Let the allocator manage the actual allocation. The user can use the
   * standard heap or provide a specific allocator with memory protection.
   */
  if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
                                   &obj->const_base, const_size,
                                   &obj->data_base, data_size,
                                   &obj->bss_base, bss_size))
  {
    obj->exec_size = 0;
    rtems_rtl_set_error (ENOMEM, "no memory to load obj");
    return false;
  }

  obj->exec_size = text_size + const_size + data_size + bss_size;

  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
  {
    printf ("rtl: load sect: text  - b:%p s:%zi a:%" PRIu32 "\n",
            obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
    printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
            obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
    printf ("rtl: load sect: data  - b:%p s:%zi a:%" PRIu32 "\n",
            obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
    printf ("rtl: load sect: bss   - b:%p s:%zi a:%" PRIu32 "\n",
            obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj));
  }

  /*
   * Load all text then data then bss sections in seperate operations so each
   * type of section is grouped together.
   */
  if (!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_TEXT,
                                      obj, fd, obj->text_base, handler, data) ||
      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
                                      obj, fd, obj->const_base, handler, data) ||
      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
                                      obj, fd, obj->data_base, handler, data) ||
      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
                                      obj, fd, obj->bss_base, handler, data))
  {
    rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
                                &obj->data_base, &obj->bss_base);
    obj->exec_size = 0;
    return false;
  }

  return true;
}
Example #20
0
bool
rtems_rtl_parse_name (const char*  name,
                      const char** aname,
                      const char** oname,
                      off_t*       ooffset)
{
  const char* laname = NULL;
  const char* loname = NULL;
  const char* colon;
  const char* end;

  /*
   * Parse the name to determine if the object file is part of an archive or it
   * is an object file. If an archive check the name for a '@' to see if the
   * archive contains an offset.
   */
  end = name + strlen (name);
  colon = strrchr (name, ':');
  if (colon == NULL || colon < strrchr(name, '/'))
    colon = end;

  loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, colon - name + 1, true);
  if (!oname)
  {
    rtems_rtl_set_error (ENOMEM, "no memory for object file name");
    return false;
  }

  memcpy ((void*) loname, name, colon - name);

  /*
   * If the pointers match there is no ':' delimiter.
   */
  if (colon != end)
  {
    const char* at;

    /*
     * The file name is an archive and the object file name is next after the
     * delimiter. Move the pointer to the archive name.
     */
    laname = loname;
    ++colon;

    /*
     * See if there is a '@' to delimit an archive offset for the object in the
     * archive.
     */
    at = strchr (colon, '@');

    if (at == NULL)
      at = end;


    loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, at - colon + 1, true);
    if (!loname)
    {
      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) laname);
      rtems_rtl_set_error (ENOMEM, "no memory for object file name");
      return false;
    }

    memcpy ((void*) loname, colon, at - colon);

    if (at != end)
    {
      /*
       * The object name has an archive offset. If the number
       * does not parse 0 will be returned and the archive will be
       * searched.
       */
      *ooffset = strtoul (at + 1, 0, 0);
    }
  }

  *oname = loname;
  *aname = laname;
  return true;
}