Esempio n. 1
0
bool lsda_init(lsda_t* lsda, exception_context_t* context)
{
  const uint8_t* data =
    (const uint8_t*)_Unwind_GetLanguageSpecificData(context);

  if(data == NULL)
    return false;

  lsda->region_start = _Unwind_GetRegionStart(context);
  //-1 because IP points past the faulting instruction
  lsda->ip = _Unwind_GetIP(context) - 1;
  lsda->ip_offset = lsda->ip - lsda->region_start;

  lsda->landing_pads = read_with_encoding(&data, lsda->region_start);
  lsda->type_table_encoding = *data++;

  if(lsda->type_table_encoding != DW_EH_PE_omit)
  {
    lsda->type_table = (const uint8_t*)read_uleb128(&data);
    lsda->type_table += (uintptr_t)data;
  } else {
    lsda->type_table = NULL;
  }

  lsda->call_site_encoding = *data++;

  uintptr_t length = read_uleb128(&data);
  lsda->call_site_table = data;
  lsda->action_table = data + length;

  return true;
}
uintptr_t MachObject::exportedSymbolAddressCompressed(Symbol *sym)
{
    const uint8_t* exportNode = (uint8_t*)(sym->addr);
    const uint8_t* start = addUintPtr2(fLinkEditBase, fDyldInfo->export_off);
    const uint8_t* end = addUintPtr3(fLinkEditBase, fDyldInfo->export_off, fDyldInfo->export_size);
    bool runResolver = true;
    uintptr_t result = 0;

    if ((exportNode < start) || (exportNode > end))
        lnk::halt("symbol not in a trie");

    uint32_t flags = read_uleb128(exportNode, end);

    if ((flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR) {
        if ( runResolver && (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) ) {
            lnk::halt("XXX: resolvers not implemented, fix macho loader on line %d", __LINE__);
            return result;
        }

        return read_uleb128(exportNode, end) + (uintptr_t)fHeader;
    }
    else if ((flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL) {
        if (flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
            lnk::halt("unsupported local exported symbol kind. flags=%d at node=%p", flags, sym);

        return read_uleb128(exportNode, end) + (uintptr_t)fHeader;
    }
    else {
        lnk::halt("unsupported exported symbol kind. flags=%d at node=%p", flags, sym);
    }
}
Esempio n. 3
0
static const unsigned char *
parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
		   lsda_header_info *info)
{
  _Unwind_Word tmp;
  unsigned char lpstart_encoding;

  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);

  /* Find @LPStart, the base to which landing pad offsets are relative.  */
  lpstart_encoding = *p++;
  if (lpstart_encoding != DW_EH_PE_omit)
    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
  else
    info->LPStart = info->Start;

  /* Find @TType, the base of the handler and exception spec type data.  */
  info->ttype_encoding = *p++;
  if (info->ttype_encoding != DW_EH_PE_omit)
    {
      p = read_uleb128 (p, &tmp);
      info->TType = p + tmp;
    }
  else
    info->TType = 0;

  /* The encoding and length of the call-site table; the action table
     immediately follows.  */
  info->call_site_encoding = *p++;
  p = read_uleb128 (p, &tmp);
  info->action_table = p + tmp;

  return p;
}
static void
get_call_site_action_for (_Unwind_Context *uw_context,
                          region_descriptor *region,
                          action_descriptor *action)
{
  _Unwind_Ptr call_site
    = _Unwind_GetIP (uw_context) - 1;
  /* Subtract 1 because GetIP returns the actual call_site value + 1.  */

  /* call_site is a direct index into the call-site table, with two special
     values : -1 for no-action and 0 for "terminate". The latter should never
     show up for Ada. To test for the former, beware that _Unwind_Ptr might be
     unsigned.  */

  if ((int)call_site < 0)
    {
      action->kind = nothing;
      return;
    }
  else if (call_site == 0)
    {
      db (DB_ERR, "========> Err, null call_site for Ada/sjlj\n");
      action->kind = nothing;
      return;
    }
  else
    {
      _uleb128_t cs_lp, cs_action;

      /* Let the caller know there may be an action to take, but let it
	 determine the kind.  */
      action->kind = unknown;

      /* We have a direct index into the call-site table, but this table is
	 made of leb128 values, the encoding length of which is variable. We
	 can't merely compute an offset from the index, then, but have to read
	 all the entries before the one of interest.  */

      const unsigned char * p = region->call_site_table;

      do {
	p = read_uleb128 (p, &cs_lp);
	p = read_uleb128 (p, &cs_action);
      } while (--call_site);


      action->landing_pad = cs_lp + 1;

      if (cs_action)
	action->table_entry = region->action_table + cs_action - 1;
      else
	action->table_entry = 0;

      return;
    }
}
Esempio n. 5
0
static int
get_cie_encoding (const struct dwarf_cie *cie)
{
  const unsigned char *aug, *p;
  _Unwind_Ptr dummy;
  _uleb128_t utmp;
  _sleb128_t stmp;

  aug = cie->augmentation;
  p = aug + strlen ((const char *)aug) + 1; /* Skip the augmentation string.  */
  if (__builtin_expect (cie->version >= 4, 0))
    {
      if (p[0] != sizeof (void *) || p[1] != 0)
	return DW_EH_PE_omit;		/* We are not prepared to handle unexpected
					   address sizes or segment selectors.  */
      p += 2;				/* Skip address size and segment size.  */
    }

  if (aug[0] != 'z')
    return DW_EH_PE_absptr;

  p = read_uleb128 (p, &utmp);		/* Skip code alignment.  */
  p = read_sleb128 (p, &stmp);		/* Skip data alignment.  */
  if (cie->version == 1)		/* Skip return address column.  */
    p++;
  else
    p = read_uleb128 (p, &utmp);

  aug++;				/* Skip 'z' */
  p = read_uleb128 (p, &utmp);		/* Skip augmentation length.  */
  while (1)
    {
      /* This is what we're looking for.  */
      if (*aug == 'R')
	return *p;
      /* Personality encoding and pointer.  */
      else if (*aug == 'P')
	{
	  /* ??? Avoid dereferencing indirect pointers, since we're
	     faking the base address.  Gotta keep DW_EH_PE_aligned
	     intact, however.  */
	  p = read_encoded_value_with_base (*p & 0x7F, 0, p + 1, &dummy);
	}
      /* LSDA encoding.  */
      else if (*aug == 'L')
	p++;
      /* Otherwise end of string, or unknown augmentation.  */
      else
	return DW_EH_PE_absptr;
      aug++;
    }
}
Esempio n. 6
0
static void
get_region_description_for (_Unwind_Context *uw_context,
                            region_descriptor *region)
{
  const unsigned char * p;
  _uleb128_t tmp;
  unsigned char lpbase_encoding;

  /* Get the base address of the lsda information. If the provided context
     is null or if there is no associated language specific data, there's
     nothing we can/should do.  */
  region->lsda
    = (_Unwind_Ptr) (uw_context
		     ? _Unwind_GetLanguageSpecificData (uw_context) : 0);

  if (! region->lsda)
    return;

  /* Parse the lsda and fill the region descriptor.  */
  p = (const unsigned char *)region->lsda;

  region->base = _Unwind_GetRegionStart (uw_context);

  /* Find @LPStart, the base to which landing pad offsets are relative.  */
  lpbase_encoding = *p++;
  if (lpbase_encoding != DW_EH_PE_omit)
    p = read_encoded_value
      (uw_context, lpbase_encoding, p, &region->lp_base);
  else
    region->lp_base = region->base;

  /* Find @TType, the base of the handler and exception spec type data.  */
  region->ttype_encoding = *p++;
  if (region->ttype_encoding != DW_EH_PE_omit)
    {
      p = read_uleb128 (p, &tmp);
      region->ttype_table = p + tmp;
    }
   else
     region->ttype_table = 0;

  region->ttype_base
    = base_of_encoded_value (region->ttype_encoding, uw_context);

  /* Get the encoding and length of the call-site table; the action table
     immediately follows.  */
  region->call_site_encoding = *p++;
  region->call_site_table = read_uleb128 (p, &tmp);

  region->action_table = region->call_site_table + tmp;
}
Esempio n. 7
0
_Unwind_Reason_Code lsda_scan(lsda_t* lsda, _Unwind_Action actions,
  uintptr_t* lp)
{
  (void)actions;
  const uint8_t* p = lsda->call_site_table;

  while(p < lsda->action_table)
  {
    uintptr_t start = read_encoded_ptr(&p, lsda->call_site_encoding);
    uintptr_t length = read_encoded_ptr(&p, lsda->call_site_encoding);
    uintptr_t landing_pad = read_encoded_ptr(&p, lsda->call_site_encoding);

    // Pony ignores the action index, since it uses only cleanup landing pads.
    read_uleb128(&p);

    if((start <= lsda->ip_offset) && (lsda->ip_offset < (start + length)))
    {
      // No landing pad.
      if(landing_pad == 0)
        return _URC_CONTINUE_UNWIND;

      // Pony doesn't read the type index or look up types. We treat cleanup
      // landing pads the same as any other landing pad.
      *lp = lsda->landing_pads + landing_pad;
      return _URC_HANDLER_FOUND;
    }
  }

  return _URC_CONTINUE_UNWIND;
}
Esempio n. 8
0
static bool
read_filename(struct dwbuf *names, const char **outdirname,
    const char **outbasename, uint8_t opcode_base, uint64_t file)
{
	if (file == 0)
		return (false);

	/* Skip over opcode table. */
	size_t i;
	for (i = 1; i < opcode_base; i++) {
		uint64_t dummy;
		if (!read_uleb128(names, &dummy))
			return (false);
	}

	/* Skip over directory name table for now. */
	struct dwbuf dirnames = *names;
	for (;;) {
		const char *name;
		if (!read_string(names, &name))
			return (false);
		if (*name == '\0')
			break;
	}

	/* Locate file entry. */
	const char *basename = NULL;
	uint64_t dir = 0;
	for (i = 0; i < file; i++) {
		uint64_t mtime, size;
		if (!read_string(names, &basename) || *basename == '\0' ||
		    !read_uleb128(names, &dir) ||
		    !read_uleb128(names, &mtime) ||
		    !read_uleb128(names, &size))
			return (false);
	}

	const char *dirname = NULL;
	for (i = 0; i < dir; i++) {
		if (!read_string(&dirnames, &dirname) || *dirname == '\0')
			return (false);
	}

	*outdirname = dirname;
	*outbasename = basename;
	return (true);
}
Esempio n. 9
0
static void
get_call_site_action_for (_Unwind_Context *uw_context,
                          region_descriptor *region,
                          action_descriptor *action)
{
  const unsigned char *p = region->call_site_table;
  _Unwind_Ptr ip = get_ip_from_context (uw_context);

  /* Unless we are able to determine otherwise...  */
  action->kind = nothing;

  db (DB_CSITE, "\n");

  while (p < region->action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _uleb128_t cs_action;

      /* Note that all call-site encodings are "absolute" displacements.  */
      p = read_encoded_value (0, region->call_site_encoding, p, &cs_start);
      p = read_encoded_value (0, region->call_site_encoding, p, &cs_len);
      p = read_encoded_value (0, region->call_site_encoding, p, &cs_lp);
      p = read_uleb128 (p, &cs_action);

      db (DB_CSITE,
	  "c_site @ %p (+%p), len = %p, lpad @ %p (+%p)\n",
	  (void *)region->base + cs_start, (void *)cs_start, (void *)cs_len,
	  (void *)region->lp_base + cs_lp, (void *)cs_lp);

      /* The table is sorted, so if we've passed the IP, stop.  */
      if (ip < region->base + cs_start)
 	break;

      /* If we have a match, fill the ACTION fields accordingly.  */
      else if (ip < region->base + cs_start + cs_len)
	{
	  /* Let the caller know there may be an action to take, but let it
	     determine the kind.  */
	  action->kind = unknown;

	  if (cs_lp)
	    action->landing_pad = region->lp_base + cs_lp;
	  else
	    action->landing_pad = 0;

	  if (cs_action)
	    action->table_entry = region->action_table + cs_action - 1;
	  else
	    action->table_entry = 0;

	  db (DB_CSITE, "+++\n");
	  return;
	}
    }

  db (DB_CSITE, "---\n");
}
Esempio n. 10
0
static int
get_cie_encoding (struct dwarf_cie *cie)
{
  const unsigned char *aug, *p;
  _Unwind_Ptr dummy;
  _Unwind_Word utmp;
  _Unwind_Sword stmp;

  aug = cie->augmentation;
  if (aug[0] != 'z')
    return DW_EH_PE_absptr;

  /* Skip the augmentation string.  */
  p = aug + strlen ((const char *) aug) + 1;
  p = read_uleb128 (p, &utmp);		/* Skip code alignment.  */
  p = read_sleb128 (p, &stmp);		/* Skip data alignment.  */
  p++;					/* Skip return address column.  */

  aug++;				/* Skip 'z' */
  p = read_uleb128 (p, &utmp);		/* Skip augmentation length.  */
  while (1)
    {
      /* This is what we're looking for.  */
      if (*aug == 'R')
	return *p;
      /* Personality encoding and pointer.  */
      else if (*aug == 'P')
	{
	  /* ??? Avoid dereferencing indirect pointers, since we're
	     faking the base address.  Gotta keep DW_EH_PE_aligned
	     intact, however.  */
	  p = read_encoded_value_with_base (*p & 0x7F, 0, p + 1, &dummy);
	}
      /* LSDA encoding.  */
      else if (*aug == 'L')
	p++;
      /* Otherwise end of string, or unknown augmentation.  */
      else
	return DW_EH_PE_absptr;
      aug++;
    }
}
Esempio n. 11
0
DexString* DexIdx::get_stringidx_fromdex(uint32_t stridx) {
  redex_assert(stridx < m_string_ids_size);
  uint32_t stroff = m_string_ids[stridx].offset;
  always_assert_log(
    stroff < ((dex_header*)m_dexbase)->file_size,
    "String data offset out of range");
  const uint8_t* dstr = m_dexbase + stroff;
  /* Strip off uleb128 size encoding */
  int utfsize = read_uleb128(&dstr);
  return DexString::make_string((const char*)dstr, utfsize);
}
Esempio n. 12
0
static const unsigned char *
parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
		   struct lsda_header_info *info)
{
  _uleb128_t tmp;
  unsigned char lpstart_encoding;

  info->Start = (context ? _Unwind_GetRegionStart (context) : 0);

  /* Find @LPStart, the base to which landing pad offsets are
     relative.  */
  lpstart_encoding = *p++;
  if (lpstart_encoding != DW_EH_PE_omit)
    p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
  else
    info->LPStart = info->Start;

  /* Find @TType, the base of the handler and exception spec type
     data.  */
  info->ttype_encoding = *p++;
  if (info->ttype_encoding != DW_EH_PE_omit)
    {
#if _GLIBCXX_OVERRIDE_TTYPE_ENCODING
      /* Older ARM EABI toolchains set this value incorrectly, so use a
	 hardcoded OS-specific format.  */
      info->ttype_encoding = _GLIBCXX_OVERRIDE_TTYPE_ENCODING;
#endif
      p = read_uleb128 (p, &tmp);
      info->TType = p + tmp;
    }
  else
    info->TType = 0;

  /* The encoding and length of the call-site table; the action table
     immediately follows.  */
  info->call_site_encoding = *p++;
  p = read_uleb128 (p, &tmp);
  info->action_table = p + tmp;

  return p;
}
Esempio n. 13
0
static GHashTable *
read_abbrev (DebuginfoData *data, unsigned char *ptr)
{
  GHashTable *h;
  unsigned int attr, entry, form;
  struct abbrev_tag *t;
  int size;

  h = g_hash_table_new_full (g_direct_hash, g_direct_equal,
                             NULL, g_free);

  while ((attr = read_uleb128 (ptr)) != 0)
    {
      size = 10;
      entry = attr;
      t = g_malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
      t->tag = read_uleb128 (ptr);
      t->nattr = 0;
      ++ptr; /* skip children flag.  */
      while ((attr = read_uleb128 (ptr)) != 0)
        {
          if (t->nattr == size)
            {
              size += 10;
              t = g_realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
            }
          form = read_uleb128 (ptr);
          if (form == 2 || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8))
            g_warning ("%s: Unknown DWARF DW_FORM_%d", data->filename, form);

          t->attr[t->nattr].attr = attr;
          t->attr[t->nattr++].form = form;
        }
      if (read_uleb128 (ptr) != 0)
        g_warning ("%s: DWARF abbreviation does not end with 2 zeros", data->filename);
      g_hash_table_insert (h, GINT_TO_POINTER (entry), t);
    }

  return h;
}
static void
dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
			   struct axs_value * value, unsigned char *data,
			   int size)
{
  if (size == 0)
    error ("Symbol \"%s\" has been optimized out.",
	   SYMBOL_PRINT_NAME (symbol));

  if (size == 1
      && data[0] >= DW_OP_reg0
      && data[0] <= DW_OP_reg31)
    {
      value->kind = axs_lvalue_register;
      value->u.reg = data[0] - DW_OP_reg0;
    }
  else if (data[0] == DW_OP_regx)
    {
      ULONGEST reg;
      read_uleb128 (data + 1, data + size, &reg);
      value->kind = axs_lvalue_register;
      value->u.reg = reg;
    }
  else if (data[0] == DW_OP_fbreg)
    {
      /* And this is worse than just minimal; we should honor the frame base
	 as above.  */
      int frame_reg;
      LONGEST frame_offset;
      unsigned char *buf_end;

      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
      if (buf_end != data + size)
	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
	       SYMBOL_PRINT_NAME (symbol));

      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
      ax_reg (ax, frame_reg);
      ax_const_l (ax, frame_offset);
      ax_simple (ax, aop_add);

      ax_const_l (ax, frame_offset);
      ax_simple (ax, aop_add);
      value->kind = axs_lvalue_memory;
    }
  else
    error ("Unsupported DWARF opcode in the location of \"%s\".",
	   SYMBOL_PRINT_NAME (symbol));
}
bool MachObject::findExportedSymbolCompressed(const char* symbol, Symbol* sym)
{
    /*
     This is a slightly tidier version of 'findExportedSymbol'
     from dyld. Still no f*****g idea what the semantics of it
     are since I suck at CS (lol, wtf is a trie?!).
     */

    /* export table sanity */
    if (fDyldInfo->export_size == 0)
        return false;

    const uint8_t* start = addUintPtr2(fLinkEditBase, fDyldInfo->export_off);
    const uint8_t* end = addUintPtr3(fLinkEditBase, fDyldInfo->export_off, fDyldInfo->export_size);

    const uint8_t* foundNodeStart = trie_walk(start, end, symbol);

    if (foundNodeStart != NULL) {
        const uint8_t* p = foundNodeStart;
        const uint32_t flags = read_uleb128(p, end);

        if (flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
            lnk::halt("no f*****g idea, honestly");
            return false;
        }
        else {
            sym->addr = (void*)foundNodeStart;
            sym->inImage = (void*)this;

            return true;
        }
    }
    else {
        return false;
    }
}
		/*
		 * This is used by the sliding function to read and execute
		 * the compressed reloc table.
		 */
		static void rebaseCompressed(struct dyld_info_command* dyldInfo,
									 macho_segment_command* linkEdit,
									 uintptr_t slide,
									 macho_segment_command** segments,
									 int segCount)
		{
			/*
			 * HARD MODE!!!
			 */

			const uint8_t* base = (uint8_t*)((linkEdit->vmaddr + slide) - linkEdit->fileoff);
			const uint8_t* start = addUintPtr2(dyldInfo->rebase_off, base);
			const uint8_t* end = addUintPtr3(dyldInfo->rebase_size, dyldInfo->rebase_off, base);
			const uint8_t* p = start;

			/*
			 * If you want a better documented version of this code, see 'MachObject.cpp'
			 */

			uint8_t type = 0;
			int segmentIndex = 0;
			uintptr_t address = (segments[0]->vmaddr + slide);
			uintptr_t segmentEndAddress = (segments[0]->vmaddr + slide + segments[0]->vmsize);
			uint32_t count;
			uint32_t skip;

			bool done = false;
			while ( !done && (p < end) ) {
				uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
				uint8_t opcode = *p & REBASE_OPCODE_MASK;

				++p;

				switch (opcode) {
					case REBASE_OPCODE_DONE:
						done = true;
						break;
					case REBASE_OPCODE_SET_TYPE_IMM:
						type = immediate;
						break;
					case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
						segmentIndex = immediate;
						if (segmentIndex > segCount)
							lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad whatever \n");

						address = (segments[segmentIndex]->vmaddr + slide) + read_uleb128(p, end);
						segmentEndAddress = (segments[segmentIndex]->vmaddr + segments[segmentIndex]->vmsize + slide);
						break;
					case REBASE_OPCODE_ADD_ADDR_ULEB:
						address += read_uleb128(p, end);
						break;
					case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
						address += immediate*sizeof(uintptr_t);
						break;
					case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
						for (int i=0; i < immediate; ++i) {
							if ( address >= segmentEndAddress )
								lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_IMM_TIMES \n");
							rebaseAt(address, slide, type);
							address += sizeof(uintptr_t);
						}
						break;
					case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
						count = read_uleb128(p, end);
						for (uint32_t i=0; i < count; ++i) {
							if ( address >= segmentEndAddress )
								lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_ULEB_TIMES \n");
							rebaseAt(address, slide, type);
							address += sizeof(uintptr_t);
						}
						break;
					case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
						if ( address >= segmentEndAddress )
							lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB \n");
						rebaseAt(address, slide, type);
						address += read_uleb128(p, end) + sizeof(uintptr_t);
						break;
					case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
						count = read_uleb128(p, end);
						skip = read_uleb128(p, end);
						for (uint32_t i=0; i < count; ++i) {
							if ( address >= segmentEndAddress )
								lnk::ldbg::printText("LNK_RELOC_ERROR: baaaad REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB \n");
							rebaseAt(address, slide, type);
							address += skip + sizeof(uintptr_t);
						}
						break;
					default:
						_printAbrt();
				}
			}
		}
Esempio n. 17
0
static gboolean
handle_dwarf2_line (DebuginfoData *data, uint32_t off, char *comp_dir, GHashTable *files, GError **error)
{
  unsigned char *ptr = data->debug_sections[DEBUG_LINE].data, *dir;
  unsigned char **dirt;
  unsigned char *endsec = ptr + data->debug_sections[DEBUG_LINE].size;
  unsigned char *endcu, *endprol;
  unsigned char opcode_base;
  uint32_t value, dirt_cnt;
  size_t comp_dir_len = !comp_dir ? 0 : strlen (comp_dir);


  /* XXX: RhBug:929365, should we error out instead of ignoring? */
  if (ptr == NULL)
    return TRUE;

  ptr += off;

  endcu = ptr + 4;
  endcu += read_32 (ptr);
  if (endcu == ptr + 0xffffffff)
    return flatpak_fail (error, "%s: 64-bit DWARF not supported", data->filename);

  if (endcu > endsec)
    return flatpak_fail (error, "%s: .debug_line CU does not fit into section", data->filename);

  value = read_16 (ptr);
  if (value != 2 && value != 3 && value != 4)
    return flatpak_fail (error, "%s: DWARF version %d unhandled", data->filename, value);

  endprol = ptr + 4;
  endprol += read_32 (ptr);
  if (endprol > endcu)
    return flatpak_fail (error, "%s: .debug_line CU prologue does not fit into CU", data->filename);

  opcode_base = ptr[4 + (value >= 4)];
  ptr = dir = ptr + 4 + (value >= 4) + opcode_base;

  /* dir table: */
  value = 1;
  while (*ptr != 0)
    {
      ptr = (unsigned char *) strchr ((char *) ptr, 0) + 1;
      ++value;
    }

  dirt = (unsigned char **) alloca (value * sizeof (unsigned char *));
  dirt[0] = (unsigned char *) ".";
  dirt_cnt = 1;
  ptr = dir;
  while (*ptr != 0)
    {
      dirt[dirt_cnt++] = ptr;
      ptr = (unsigned char *) strchr ((char *) ptr, 0) + 1;
    }
  ptr++;

  /* file table: */
  while (*ptr != 0)
    {
      char *s, *file;
      size_t file_len, dir_len;

      file = (char *) ptr;
      ptr = (unsigned char *) strchr ((char *) ptr, 0) + 1;
      value = read_uleb128 (ptr);

      if (value >= dirt_cnt)
        return flatpak_fail (error, "%s: Wrong directory table index %u",  data->filename, value);

      file_len = strlen (file);
      dir_len = strlen ((char *) dirt[value]);
      s = g_malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1);
      if (*file == '/')
        {
          memcpy (s, file, file_len + 1);
        }
      else if (*dirt[value] == '/')
        {
          memcpy (s, dirt[value], dir_len);
          s[dir_len] = '/';
          memcpy (s + dir_len + 1, file, file_len + 1);
        }
      else
        {
          char *p = s;
          if (comp_dir_len != 0)
            {
              memcpy (s, comp_dir, comp_dir_len);
              s[comp_dir_len] = '/';
              p += comp_dir_len + 1;
            }
          memcpy (p, dirt[value], dir_len);
          p[dir_len] = '/';
          memcpy (p + dir_len + 1, file, file_len + 1);
        }
      canonicalize_path (s, s);

      if (s)
        g_hash_table_insert (files, s, NULL);

      (void) read_uleb128 (ptr);
      (void) read_uleb128 (ptr);
    }
  ++ptr;

  return TRUE;
}
Esempio n. 18
0
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
#endif
{
  struct ObjcException *xh = (struct ObjcException *) ue_header;

  struct lsda_header_info info;
  const unsigned char *language_specific_data;
  const unsigned char *action_record;
  const unsigned char *p;
  _Unwind_Ptr landing_pad, ip;
  int handler_switch_value;
  int saw_cleanup = 0, saw_handler;
  void *return_object;
  int foreign_exception;
  int ip_before_insn = 0;

#ifdef __ARM_EABI_UNWINDER__
  _Unwind_Action actions;

  switch (state & _US_ACTION_MASK)
    {
    case _US_VIRTUAL_UNWIND_FRAME:
      actions = _UA_SEARCH_PHASE;
      break;

    case _US_UNWIND_FRAME_STARTING:
      actions = _UA_CLEANUP_PHASE;
      if (!(state & _US_FORCE_UNWIND)
	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
	actions |= _UA_HANDLER_FRAME;
      break;

    case _US_UNWIND_FRAME_RESUME:
      CONTINUE_UNWINDING;
      break;

    default:
      abort();
    }
  actions |= state & _US_FORCE_UNWIND;

  foreign_exception = 0;

  ip = (_Unwind_Ptr) ue_header;
  _Unwind_SetGR(context, 12, ip);
#else
  /* Interface version check.  */
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;
  foreign_exception = !(exception_class == __objc_exception_class);
#endif

  /* Shortcut for phase 2 found handler for domestic exception.  */
  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
      && !foreign_exception)
    {
#ifdef __ARM_EABI_UNWINDER__
      handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1];
      landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3];
#else
      handler_switch_value = xh->handlerSwitchValue;
      landing_pad = xh->landingPad;
#endif
      goto install_context;
    }

  language_specific_data = (const unsigned char *)
    _Unwind_GetLanguageSpecificData (context);

  /* If no LSDA, then there are no handlers or cleanups.  */
  if (! language_specific_data)
    CONTINUE_UNWINDING;

  /* Parse the LSDA header.  */
  p = parse_lsda_header (context, language_specific_data, &info);
  info.ttype_base = base_of_encoded_value (info.ttype_encoding, context);
#ifdef HAVE_GETIPINFO
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
  ip = _Unwind_GetIP (context);
#endif
  if (! ip_before_insn)
    --ip;
  landing_pad = 0;
  action_record = 0;
  handler_switch_value = 0;

#ifdef SJLJ_EXCEPTIONS
  /* The given "IP" is an index into the call-site table, with two
     exceptions -- -1 means no-action, and 0 means terminate.  But
     since we're using uleb128 values, we've not got random access
     to the array.  */
  if ((int) ip < 0)
    return _URC_CONTINUE_UNWIND;
  else
    {
      _Unwind_Word cs_lp, cs_action;
      do
	{
	  p = read_uleb128 (p, &cs_lp);
	  p = read_uleb128 (p, &cs_action);
	}
      while (--ip);

      /* Can never have null landing pad for sjlj -- that would have
         been indicated by a -1 call site index.  */
      landing_pad = cs_lp + 1;
      if (cs_action)
	action_record = info.action_table + cs_action - 1;
      goto found_something;
    }
#else
  /* Search the call-site table for the action associated with this IP.  */
  while (p < info.action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _Unwind_Word cs_action;

      /* Note that all call-site encodings are "absolute" displacements.  */
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
      p = read_uleb128 (p, &cs_action);

      /* The table is sorted, so if we've passed the ip, stop.  */
      if (ip < info.Start + cs_start)
	p = info.action_table;
      else if (ip < info.Start + cs_start + cs_len)
	{
	  if (cs_lp)
	    landing_pad = info.LPStart + cs_lp;
	  if (cs_action)
	    action_record = info.action_table + cs_action - 1;
	  goto found_something;
	}
    }
#endif /* SJLJ_EXCEPTIONS  */

  /* If ip is not present in the table, C++ would call terminate.  */
  /* ??? As with Java, it's perhaps better to tweek the LSDA to
     that no-action is mapped to no-entry.  */
  return _URC_CONTINUE_UNWIND;

 found_something:
  saw_cleanup = 0;
  saw_handler = 0;

  if (landing_pad == 0)
    {
      /* If ip is present, and has a null landing pad, there are
	 no cleanups or handlers to be run.  */
    }
  else if (action_record == 0)
    {
      /* If ip is present, has a non-null landing pad, and a null
         action table offset, then there are only cleanups present.
         Cleanups use a zero switch value, as set above.  */
      saw_cleanup = 1;
    }
  else
    {
      /* Otherwise we have a catch handler.  */
      _Unwind_Sword ar_filter, ar_disp;

      while (1)
	{
	  p = action_record;
	  p = read_sleb128 (p, &ar_filter);
	  read_sleb128 (p, &ar_disp);

	  if (ar_filter == 0)
	    {
	      /* Zero filter values are cleanups.  */
	      saw_cleanup = 1;
	    }

	  /* During forced unwinding, we only run cleanups.  With a
	     foreign exception class, we have no class info to match.  */
	  else if ((actions & _UA_FORCE_UNWIND)
		   || foreign_exception)
	    ;

	  else if (ar_filter > 0)
	    {
	      /* Positive filter values are handlers.  */

	      Class catch_type = get_ttype_entry (&info, ar_filter);

	      if (isKindOf (xh->value, catch_type))
		{
		  handler_switch_value = ar_filter;
		  saw_handler = 1;
		  break;
		}
	    }
	  else
	    {
	      /* Negative filter values are exception specifications,
	         which Objective-C does not use.  */
	      abort ();
	    }

	  if (ar_disp == 0)
	    break;
	  action_record = p + ar_disp;
	}
    }

  if (! saw_handler && ! saw_cleanup)
    CONTINUE_UNWINDING;

  if (actions & _UA_SEARCH_PHASE)
    {
      if (!saw_handler)
	CONTINUE_UNWINDING;

      /* For domestic exceptions, we cache data from phase 1 for phase 2.  */
      if (!foreign_exception)
        {
#ifdef __ARM_EABI_UNWIDER__
	  ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13);
	  ue_header->barrier_cache.bitpattern[1]
	    = (_uw) handler_switch_value;
	  ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad;
#else
          xh->handlerSwitchValue = handler_switch_value;
          xh->landingPad = landing_pad;
#endif
	}
      return _URC_HANDLER_FOUND;
    }

 install_context:
  if (saw_cleanup == 0)
    {
      return_object = xh->value;
      if (!(actions & _UA_SEARCH_PHASE))
	_Unwind_DeleteException(&xh->base);
    }
  
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 __builtin_extend_pointer (saw_cleanup ? xh : return_object));
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
		 handler_switch_value);
  _Unwind_SetIP (context, landing_pad);
  return _URC_INSTALL_CONTEXT;
}
Esempio n. 19
0
_Unwind_Reason_Code __runa_personality(int version,
  _Unwind_Action actions, _Unwind_Exception_Class exception_class,
  struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) {

  enum found_handler_type {
    found_nothing, found_terminate, found_cleanup, found_handler
  } found_type;

  struct lsda_header_info info;
  const unsigned char *language_specific_data;
  const unsigned char *action_record;
  const unsigned char *p;
  _Unwind_Ptr landing_pad, ip;
  int handler_switch_value;
  void* thrown_ptr = 0;
  bool foreign_exception;
  int ip_before_insn = 0;

  //__cxa_exception* xh = __get_exception_header_from_ue(ue_header);

  // Interface version check.
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;

  foreign_exception = exception_class != RUNA_CLASS;

  // Shortcut for phase 2 found handler for domestic exception.
  if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) && !foreign_exception) {
    restore_caught_exception(ue_header, &handler_switch_value,
                             &language_specific_data, &landing_pad);
    found_type = (landing_pad == 0 ? found_terminate : found_handler);
    goto install_context;
  }

  language_specific_data = (const unsigned char *) _Unwind_GetLanguageSpecificData(context);

  // If no LSDA, then there are no handlers or cleanups.
  if (!language_specific_data)
    return _URC_CONTINUE_UNWIND;

  // Parse the LSDA header.
  p = parse_lsda_header(context, language_specific_data, &info);
  info.ttype_base = base_of_encoded_value(info.ttype_encoding, context);
  ip = _Unwind_GetIPInfo(context, &ip_before_insn);
  //ip = _Unwind_GetIP(context);
  if (!ip_before_insn)
    --ip;

  landing_pad = 0;
  action_record = 0;
  handler_switch_value = 0;

  // Search the call-site table for the action associated with this IP.
  while (p < info.action_table) {

    _Unwind_Ptr cs_start, cs_len, cs_lp;
    _uleb128_t cs_action;

    // Note that all call-site encodings are "absolute" displacements.
    p = read_encoded_value(0, info.call_site_encoding, p, &cs_start);
    p = read_encoded_value(0, info.call_site_encoding, p, &cs_len);
    p = read_encoded_value(0, info.call_site_encoding, p, &cs_lp);
    p = read_uleb128(p, &cs_action);

    // The table is sorted, so if we've passed the ip, stop.
    if (ip < info.Start + cs_start) {
      p = info.action_table;
    } else if (ip < info.Start + cs_start + cs_len) {
      if (cs_lp)
        landing_pad = info.LPStart + cs_lp;
      if (cs_action)
        action_record = info.action_table + cs_action - 1;
      goto found_something;
    }

  }

  // If ip is not present in the table, call terminate. This is for
  // a destructor inside a cleanup, or a library routine the compiler
  // was not expecting to throw.
  found_type = found_terminate;
  goto do_something;

 found_something:
  if (landing_pad == 0) {
    // If ip is present, and has a null landing pad, there are
    // no cleanups or handlers to be run.
    found_type = found_nothing;
  } else if (action_record == 0) {
    // If ip is present, has a non-null landing pad, and a null
    // action table offset, then there are only cleanups present.
    // Cleanups use a zero switch value, as set above.
    found_type = found_cleanup;
  } else {

    // Otherwise we have a catch handler or exception specification.
    _sleb128_t ar_filter, ar_disp;
    //const std::type_info* catch_type;
    //_throw_typet* throw_type;
    bool saw_cleanup = false;
    bool saw_handler = false;

    {
      //thrown_ptr = __get_object_from_ue(ue_header);
      //throw_type = __get_exception_header_from_obj(thrown_ptr)->exceptionType;
    }

    while (1) {

      p = action_record;
      p = read_sleb128(p, &ar_filter);
      read_sleb128(p, &ar_disp);

      if (ar_filter == 0) {
        // Zero filter values are cleanups.
        saw_cleanup = true;
      } else if (ar_filter > 0) {

        // Positive filter values are handlers.
        //catch_type = get_ttype_entry(&info, ar_filter);
        //printf("positive filter value -- handler found\n");
        saw_handler = true;
        break;

        // Null catch type is a catch-all handler; we can catch foreign
        // exceptions with this. Otherwise we must match types.

        //if (!catch_type || (throw_type &&
        //                    get_adjusted_ptr(catch_type, throw_type, &thrown_ptr))) {
        //  saw_handler = true;
        //  break;
        //}

      } else {

        printf("negative filter value -- exception spec\n");
        // Negative filter values are exception specifications.
        // ??? How do foreign exceptions fit in?  As far as I can
        // see we can't match because there's no __cxa_exception
        // object to stuff bits in for __cxa_call_unexpected to use.
        // Allow them iff the exception spec is non-empty.  I.e.
        // a throw() specification results in __unexpected.

        //if ((throw_type && !(actions & _UA_FORCE_UNWIND) && !foreign_exception) ?
        //    !check_exception_spec(&info, throw_type, thrown_ptr, ar_filter) :
        //    empty_exception_spec(&info, ar_filter)) {
        //  saw_handler = true;
        //  break;
        //}

      }

      if (ar_disp == 0)
        break;
      action_record = p + ar_disp;

    }

    if (saw_handler) {
      handler_switch_value = ar_filter;
      found_type = found_handler;
    } else {
      found_type = (saw_cleanup ? found_cleanup : found_nothing);
    }

  }

 do_something:

   if (found_type == found_nothing)
     return _URC_CONTINUE_UNWIND;

  if (actions & _UA_SEARCH_PHASE) {

    if (found_type == found_cleanup)
      return _URC_CONTINUE_UNWIND;

    // For domestic exceptions, we cache data from phase 1 for phase 2.
    if (!foreign_exception) {
      save_caught_exception(ue_header, handler_switch_value,
                            language_specific_data, landing_pad);
    }

    return _URC_HANDLER_FOUND;
  }

 install_context:

  // We can't use any of the cxa routines with foreign exceptions,
  // because they all expect ue_header to be a struct __cxa_exception.
  // So in that case, call terminate or unexpected directly.
  if ((actions & _UA_FORCE_UNWIND) || foreign_exception) {

    if (found_type == found_terminate)
      abort(); // std::terminate();
    else if (handler_switch_value < 0) {
      printf("WTF\n");
      //__try
      //  { std::unexpected (); }
      //__catch(...)
      //  { std::terminate (); }
    }

  } else {

    if (found_type == found_terminate)
      abort(); //__cxa_call_terminate(ue_header);

    // Cache the TType base value for __cxa_call_unexpected, as we won't
    // have an _Unwind_Context then.
    if (handler_switch_value < 0) {
      parse_lsda_header(context, language_specific_data, &info);
      info.ttype_base = base_of_encoded_value(info.ttype_encoding, context);
      //xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context);
    }

  }

  /* For targets with pointers smaller than the word size, we must extend the
     pointer, and this extension is target dependent.  */
  _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), __builtin_extend_pointer(ue_header));
  _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), handler_switch_value);
  _Unwind_SetIP(context, landing_pad);
  return _URC_INSTALL_CONTEXT;

}
Esempio n. 20
0
_Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
#endif
{
  lsda_header_info info;
  const unsigned char *language_specific_data, *p, *action_record;
  _Unwind_Ptr landing_pad, ip;
  int ip_before_insn = 0;
  _Bool is_foreign;
  G *g;

#ifdef __ARM_EABI_UNWINDER__
  _Unwind_Action actions;

  switch (state & _US_ACTION_MASK)
    {
    case _US_VIRTUAL_UNWIND_FRAME:
      actions = _UA_SEARCH_PHASE;
      break;

    case _US_UNWIND_FRAME_STARTING:
      actions = _UA_CLEANUP_PHASE;
      if (!(state & _US_FORCE_UNWIND)
	  && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
	actions |= _UA_HANDLER_FRAME;
      break;

    case _US_UNWIND_FRAME_RESUME:
      CONTINUE_UNWINDING;
      break;

    default:
      abort();
    }
  actions |= state & _US_FORCE_UNWIND;

  is_foreign = 0;

  /* The dwarf unwinder assumes the context structure holds things like the
     function and LSDA pointers.  The ARM implementation caches these in
     the exception header (UCB).  To avoid rewriting everything we make the
     virtual IP register point at the UCB.  */
  ip = (_Unwind_Ptr) ue_header;
  _Unwind_SetGR (context, 12, ip);
#else
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;

  is_foreign = exception_class != __go_exception_class;
#endif

  language_specific_data = (const unsigned char *)
    _Unwind_GetLanguageSpecificData (context);

  /* If no LSDA, then there are no handlers or cleanups.  */
  if (! language_specific_data)
    CONTINUE_UNWINDING;

  /* Parse the LSDA header.  */
  p = parse_lsda_header (context, language_specific_data, &info);
#ifdef HAVE_GETIPINFO
  ip = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
  ip = _Unwind_GetIP (context);
#endif
  if (! ip_before_insn)
    --ip;
  landing_pad = 0;
  action_record = NULL;

#ifdef __USING_SJLJ_EXCEPTIONS__
  /* The given "IP" is an index into the call-site table, with two
     exceptions -- -1 means no-action, and 0 means terminate.  But
     since we're using uleb128 values, we've not got random access
     to the array.  */
  if ((int) ip <= 0)
    return _URC_CONTINUE_UNWIND;
  else
    {
      _uleb128_t cs_lp, cs_action;
      do
	{
	  p = read_uleb128 (p, &cs_lp);
	  p = read_uleb128 (p, &cs_action);
	}
      while (--ip);

      /* Can never have null landing pad for sjlj -- that would have
	 been indicated by a -1 call site index.  */
      landing_pad = (_Unwind_Ptr)cs_lp + 1;
      if (cs_action)
	action_record = info.action_table + cs_action - 1;
      goto found_something;
    }
#else
  /* Search the call-site table for the action associated with this IP.  */
  while (p < info.action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _uleb128_t cs_action;

      /* Note that all call-site encodings are "absolute" displacements.  */
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
      p = read_uleb128 (p, &cs_action);

      /* The table is sorted, so if we've passed the ip, stop.  */
      if (ip < info.Start + cs_start)
	p = info.action_table;
      else if (ip < info.Start + cs_start + cs_len)
	{
	  if (cs_lp)
	    landing_pad = info.LPStart + cs_lp;
	  if (cs_action)
	    action_record = info.action_table + cs_action - 1;
	  goto found_something;
	}
    }
#endif

  /* IP is not in table.  No associated cleanups.  */
  CONTINUE_UNWINDING;

 found_something:
  if (landing_pad == 0)
    {
      /* IP is present, but has a null landing pad.
	 No handler to be run.  */
      CONTINUE_UNWINDING;
    }

  if (actions & _UA_SEARCH_PHASE)
    {
      if (action_record == 0)
	{
	  /* This indicates a cleanup rather than an exception
	     handler.  */
	  CONTINUE_UNWINDING;
	}

      return _URC_HANDLER_FOUND;
    }

  /* It's possible for g to be NULL here for an exception thrown by a
     language other than Go.  */
  g = runtime_g ();
  if (g == NULL)
    {
      if (!is_foreign)
	abort ();
    }
  else
    {
      g->exception = ue_header;
      g->isforeign = is_foreign;
    }

  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 (_Unwind_Ptr) ue_header);
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
  _Unwind_SetIP (context, landing_pad);
  return _URC_INSTALL_CONTEXT;
}
static void
dwarf2_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
			   struct axs_value *value, gdb_byte *data,
			   int size)
{
  if (size == 0)
    error (_("Symbol \"%s\" has been optimized out."),
	   SYMBOL_PRINT_NAME (symbol));

  if (size == 1
      && data[0] >= DW_OP_reg0
      && data[0] <= DW_OP_reg31)
    {
      value->kind = axs_lvalue_register;
      value->u.reg = data[0] - DW_OP_reg0;
    }
  else if (data[0] == DW_OP_regx)
    {
      ULONGEST reg;
      read_uleb128 (data + 1, data + size, &reg);
      value->kind = axs_lvalue_register;
      value->u.reg = reg;
    }
  else if (data[0] == DW_OP_fbreg)
    {
      /* And this is worse than just minimal; we should honor the frame base
	 as above.  */
      int frame_reg;
      LONGEST frame_offset;
      gdb_byte *buf_end;

      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
      if (buf_end != data + size)
	error (_("Unexpected opcode after DW_OP_fbreg for symbol \"%s\"."),
	       SYMBOL_PRINT_NAME (symbol));

      gdbarch_virtual_frame_pointer (current_gdbarch, 
				     ax->scope, &frame_reg, &frame_offset);
      ax_reg (ax, frame_reg);
      ax_const_l (ax, frame_offset);
      ax_simple (ax, aop_add);

      value->kind = axs_lvalue_memory;
    }
  else if (data[0] >= DW_OP_breg0
	   && data[0] <= DW_OP_breg31)
    {
      unsigned int reg;
      LONGEST offset;
      gdb_byte *buf_end;

      reg = data[0] - DW_OP_breg0;
      buf_end = read_sleb128 (data + 1, data + size, &offset);
      if (buf_end != data + size)
	error (_("Unexpected opcode after DW_OP_breg%u for symbol \"%s\"."),
	       reg, SYMBOL_PRINT_NAME (symbol));

      ax_reg (ax, reg);
      ax_const_l (ax, offset);
      ax_simple (ax, aop_add);

      value->kind = axs_lvalue_memory;
    }
  else
    error (_("Unsupported DWARF opcode 0x%x in the location of \"%s\"."),
	   data[0], SYMBOL_PRINT_NAME (symbol));
}
Esempio n. 22
0
static unsigned char *
handle_attributes (DebuginfoData *data, unsigned char *ptr, struct abbrev_tag *t, GHashTable *files, GError **error)
{
  int i;
  uint32_t list_offs;
  int found_list_offs;
  g_autofree char *comp_dir = NULL;

  comp_dir = NULL;
  list_offs = 0;
  found_list_offs = 0;
  for (i = 0; i < t->nattr; ++i)
    {
      uint32_t form = t->attr[i].form;
      size_t len = 0;

      while (1)
        {
          if (t->attr[i].attr == DW_AT_stmt_list)
            {
              if (form == DW_FORM_data4 ||
                  form == DW_FORM_sec_offset)
                {
                  list_offs = do_read_32_relocated (ptr);
                  found_list_offs = 1;
                }
            }

          if (t->attr[i].attr == DW_AT_comp_dir)
            {
              if (form == DW_FORM_string)
                {
                  g_free (comp_dir);
                  comp_dir = g_strdup ((char *) ptr);
                }
              else if (form == DW_FORM_strp &&
                       data->debug_sections[DEBUG_STR].data)
                {
                  char *dir;

                  dir = (char *) data->debug_sections[DEBUG_STR].data
                        + do_read_32_relocated (ptr);

                  g_free (comp_dir);
                  comp_dir = g_strdup (dir);
                }
            }
          else if ((t->tag == DW_TAG_compile_unit ||
                    t->tag == DW_TAG_partial_unit) &&
                   t->attr[i].attr == DW_AT_name &&
                   form == DW_FORM_strp &&
                   data->debug_sections[DEBUG_STR].data)
            {
              char *name;

              name = (char *) data->debug_sections[DEBUG_STR].data
                     + do_read_32_relocated (ptr);
              if (*name == '/' && comp_dir == NULL)
                {
                  char *enddir = strrchr (name, '/');

                  if (enddir != name)
                    {
                      comp_dir = g_malloc (enddir - name + 1);
                      memcpy (comp_dir, name, enddir - name);
                      comp_dir[enddir - name] = '\0';
                    }
                  else
                    {
                      comp_dir = g_strdup ("/");
                    }
                }

            }

          switch (form)
            {
            case DW_FORM_ref_addr:
              if (cu_version == 2)
                ptr += ptr_size;
              else
                ptr += 4;
              break;

            case DW_FORM_flag_present:
              break;

            case DW_FORM_addr:
              ptr += ptr_size;
              break;

            case DW_FORM_ref1:
            case DW_FORM_flag:
            case DW_FORM_data1:
              ++ptr;
              break;

            case DW_FORM_ref2:
            case DW_FORM_data2:
              ptr += 2;
              break;

            case DW_FORM_ref4:
            case DW_FORM_data4:
            case DW_FORM_sec_offset:
              ptr += 4;
              break;

            case DW_FORM_ref8:
            case DW_FORM_data8:
            case DW_FORM_ref_sig8:
              ptr += 8;
              break;

            case DW_FORM_sdata:
            case DW_FORM_ref_udata:
            case DW_FORM_udata:
              (void) read_uleb128 (ptr);
              break;

            case DW_FORM_strp:
              ptr += 4;
              break;

            case DW_FORM_string:
              ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1;
              break;

            case DW_FORM_indirect:
              form = read_uleb128 (ptr);
              continue;

            case DW_FORM_block1:
              len = *ptr++;
              break;

            case DW_FORM_block2:
              len = read_16 (ptr);
              form = DW_FORM_block1;
              break;

            case DW_FORM_block4:
              len = read_32 (ptr);
              form = DW_FORM_block1;
              break;

            case DW_FORM_block:
            case DW_FORM_exprloc:
              len = read_uleb128 (ptr);
              form = DW_FORM_block1;
              g_assert (len < UINT_MAX);
              break;

            default:
              g_warning ("%s: Unknown DWARF DW_FORM_%d", data->filename, form);
              return NULL;
            }

          if (form == DW_FORM_block1)
            ptr += len;

          break;
        }
    }

  /* Ensure the CU current directory will exist even if only empty.  Source
     filenames possibly located in its parent directories refer relatively to
     it and the debugger (GDB) cannot safely optimize out the missing
     CU current dir subdirectories.  */
  if (comp_dir)
    g_hash_table_insert (files, g_strdup (comp_dir), NULL);

  if (found_list_offs &&
      !handle_dwarf2_line (data, list_offs, comp_dir, files, error))
    return NULL;

  return ptr;
}
Esempio n. 23
0
static gboolean
handle_dwarf2_section (DebuginfoData *data, GHashTable *files, GError **error)
{
  Elf_Data *e_data;
  int i;
  debug_section_t *debug_sections;

  ptr_size = 0;

  if (data->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
    {
      do_read_16 = buf_read_ule16;
      do_read_32 = buf_read_ule32;
    }
  else if (data->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
    {
      do_read_16 = buf_read_ube16;
      do_read_32 = buf_read_ube32;
    }
  else
    {
      return flatpak_fail (error, "%s: Wrong ELF data encoding", data->filename);
    }

  debug_sections = data->debug_sections;

  if (debug_sections[DEBUG_INFO].data != NULL)
    {
      unsigned char *ptr, *endcu, *endsec;
      uint32_t value;
      struct abbrev_tag *t;
      g_autofree REL *relbuf = NULL;

      if (debug_sections[DEBUG_INFO].relsec)
        {
          Elf_Scn *scn;
          int ndx, maxndx;
          GElf_Rel rel;
          GElf_Rela rela;
          GElf_Sym sym;
          GElf_Addr base = data->shdr[debug_sections[DEBUG_INFO].sec].sh_addr;
          Elf_Data *symdata = NULL;
          int rtype;

          i = debug_sections[DEBUG_INFO].relsec;
          scn = data->scns[i];
          e_data = elf_getdata (scn, NULL);
          g_assert (e_data != NULL && e_data->d_buf != NULL);
          g_assert (elf_getdata (scn, e_data) == NULL);
          g_assert (e_data->d_off == 0);
          g_assert (e_data->d_size == data->shdr[i].sh_size);
          maxndx = data->shdr[i].sh_size / data->shdr[i].sh_entsize;
          relbuf = g_malloc (maxndx * sizeof (REL));
          reltype = data->shdr[i].sh_type;

          symdata = elf_getdata (data->scns[data->shdr[i].sh_link], NULL);
          g_assert (symdata != NULL && symdata->d_buf != NULL);
          g_assert (elf_getdata (data->scns[data->shdr[i].sh_link], symdata) == NULL);
          g_assert (symdata->d_off == 0);
          g_assert (symdata->d_size == data->shdr[data->shdr[i].sh_link].sh_size);

          for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
            {
              if (data->shdr[i].sh_type == SHT_REL)
                {
                  gelf_getrel (e_data, ndx, &rel);
                  rela.r_offset = rel.r_offset;
                  rela.r_info = rel.r_info;
                  rela.r_addend = 0;
                }
              else
                {
                  gelf_getrela (e_data, ndx, &rela);
                }
              gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
              /* Relocations against section symbols are uninteresting
                 in REL.  */
              if (data->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
                continue;
              /* Only consider relocations against .debug_str, .debug_line
                 and .debug_abbrev.  */
              if (sym.st_shndx != debug_sections[DEBUG_STR].sec &&
                  sym.st_shndx != debug_sections[DEBUG_LINE].sec &&
                  sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
                continue;
              rela.r_addend += sym.st_value;
              rtype = ELF64_R_TYPE (rela.r_info);
              switch (data->ehdr.e_machine)
                {
                case EM_SPARC:
                case EM_SPARC32PLUS:
                case EM_SPARCV9:
                  if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
                    goto fail;
                  break;

                case EM_386:
                  if (rtype != R_386_32)
                    goto fail;
                  break;

                case EM_PPC:
                case EM_PPC64:
                  if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
                    goto fail;
                  break;

                case EM_S390:
                  if (rtype != R_390_32)
                    goto fail;
                  break;

                case EM_IA_64:
                  if (rtype != R_IA64_SECREL32LSB)
                    goto fail;
                  break;

                case EM_X86_64:
                  if (rtype != R_X86_64_32)
                    goto fail;
                  break;

                case EM_ALPHA:
                  if (rtype != R_ALPHA_REFLONG)
                    goto fail;
                  break;

#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32)
                case EM_AARCH64:
                  if (rtype != R_AARCH64_ABS32)
                    goto fail;
                  break;

#endif
                case EM_68K:
                  if (rtype != R_68K_32)
                    goto fail;
                  break;

                default:
fail:
                  return flatpak_fail (error, "%s: Unhandled relocation %d in .debug_info section",
                                       data->filename, rtype);
                }
              relend->ptr = debug_sections[DEBUG_INFO].data
                            + (rela.r_offset - base);
              relend->addend = rela.r_addend;
              ++relend;
            }
          if (relbuf == relend)
            {
              g_free (relbuf);
              relbuf = NULL;
              relend = NULL;
            }
          else
            {
              qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
            }
        }

      ptr = debug_sections[DEBUG_INFO].data;
      relptr = relbuf;
      endsec = ptr + debug_sections[DEBUG_INFO].size;
      while (ptr != NULL && ptr < endsec)
        {
          g_autoptr(GHashTable) abbrev = NULL;

          if (ptr + 11 > endsec)
            return flatpak_fail (error, "%s: .debug_info CU header too small", data->filename);

          endcu = ptr + 4;
          endcu += read_32 (ptr);
          if (endcu == ptr + 0xffffffff)
            return flatpak_fail (error, "%s: 64-bit DWARF not supported", data->filename);

          if (endcu > endsec)
            return flatpak_fail (error, "%s: .debug_info too small", data->filename);

          cu_version = read_16 (ptr);
          if (cu_version != 2 && cu_version != 3 && cu_version != 4)
            return flatpak_fail (error, "%s: DWARF version %d unhandled", data->filename, cu_version);

          value = read_32_relocated (ptr);
          if (value >= debug_sections[DEBUG_ABBREV].size)
            {
              if (debug_sections[DEBUG_ABBREV].data == NULL)
                return flatpak_fail (error, "%s: .debug_abbrev not present", data->filename);
              else
                return flatpak_fail (error, "%s: DWARF CU abbrev offset too large", data->filename);
            }

          if (ptr_size == 0)
            {
              ptr_size = read_1 (ptr);
              if (ptr_size != 4 && ptr_size != 8)
                return flatpak_fail (error, "%s: Invalid DWARF pointer size %d", data->filename, ptr_size);
            }
          else if (read_1 (ptr) != ptr_size)
            {
              return flatpak_fail (error, "%s: DWARF pointer size differs between CUs", data->filename);
            }

          abbrev = read_abbrev (data,
                                debug_sections[DEBUG_ABBREV].data + value);

          while (ptr < endcu)
            {
              guint entry = read_uleb128 (ptr);
              if (entry == 0)
                continue;
              t = g_hash_table_lookup (abbrev, GINT_TO_POINTER (entry));
              if (t == NULL)
                {
                  g_warning ("%s: Could not find DWARF abbreviation %d", data->filename, entry);
                }
              else
                {
                  ptr = handle_attributes (data, ptr, t, files, error);
                  if (ptr == NULL)
                    return FALSE;
                }
            }
        }
    }

  return TRUE;
}
Esempio n. 24
0
bool
db_dwarf_line_at_pc(const char *linetab, size_t linetabsize, uintptr_t pc,
    const char **outdirname, const char **outbasename, int *outline)
{
	struct dwbuf table = { .buf = linetab, .len = linetabsize };

	/*
	 * For simplicity, we simply brute force search through the entire
	 * line table each time.
	 */
	uint32_t unitsize;
	struct dwbuf unit;
next:
	/* Line tables are a sequence of compilation unit entries. */
	if (!read_u32(&table, &unitsize) || unitsize >= 0xfffffff0 ||
	    !read_buf(&table, &unit, unitsize))
		return (false);

	uint16_t version;
	uint32_t header_size;
	if (!read_u16(&unit, &version) || version > 2 ||
	    !read_u32(&unit, &header_size))
		goto next;

	struct dwbuf headerstart = unit;
	uint8_t min_insn_length, default_is_stmt, line_range, opcode_base;
	int8_t line_base;
	if (!read_u8(&unit, &min_insn_length) ||
	    !read_u8(&unit, &default_is_stmt) ||
	    !read_s8(&unit, &line_base) ||
	    !read_u8(&unit, &line_range) ||
	    !read_u8(&unit, &opcode_base))
		goto next;

	/*
	 * Directory and file names are next in the header, but for now we
	 * skip directly to the line number program.
	 */
	struct dwbuf names = unit;
	unit = headerstart;
	if (!skip_bytes(&unit, header_size))
		return (false);

	/* VM registers. */
	uint64_t address = 0, file = 1, line = 1, column = 0;
	uint8_t is_stmt = default_is_stmt;
	bool basic_block = false, end_sequence = false;
	bool prologue_end = false, epilogue_begin = false;

	/* Last line table entry emitted, if any. */
	bool have_last = false;
	uint64_t last_line = 0, last_file = 0;

	/* Time to run the line program. */
	uint8_t opcode;
	while (read_u8(&unit, &opcode)) {
		bool emit = false, reset_basic_block = false;

		if (opcode >= opcode_base) {
			/* "Special" opcodes. */
			uint8_t diff = opcode - opcode_base;
			address += diff / line_range;
			line += line_base + diff % line_range;
			emit = true;
		} else if (opcode == 0) {
			/* "Extended" opcodes. */
			uint64_t extsize;
			struct dwbuf extra;
			if (!read_uleb128(&unit, &extsize) ||
			    !read_buf(&unit, &extra, extsize) ||
			    !read_u8(&extra, &opcode))
				goto next;
			switch (opcode) {
			case DW_LNE_end_sequence:
				emit = true;
				end_sequence = true;
				break;
			case DW_LNE_set_address:
				switch (extra.len) {
				case 4: {
					uint32_t address32;
					if (!read_u32(&extra, &address32))
						goto next;
					address = address32;
					break;
				}
				case 8:
					if (!read_u64(&extra, &address))
						goto next;
					break;
				default:
					DWARN("unexpected address length: %zu",
					    extra.len);
					goto next;
				}
				break;
			case DW_LNE_define_file:
				/* XXX: hope this isn't needed */
			default:
				DWARN("unknown extended opcode: %d", opcode);
				goto next;
			}
		} else {
			/* "Standard" opcodes. */
			switch (opcode) {
			case DW_LNS_copy:
				emit = true;
				reset_basic_block = true;
				break;
			case DW_LNS_advance_pc: {
				uint64_t delta;
				if (!read_uleb128(&unit, &delta))
					goto next;
				address += delta * min_insn_length;
				break;
			}
			case DW_LNS_advance_line: {
				int64_t delta;
				if (!read_sleb128(&unit, &delta))
					goto next;
				line += delta;
				break;
			}
			case DW_LNS_set_file:
				if (!read_uleb128(&unit, &file))
					goto next;
				break;
			case DW_LNS_set_column:
				if (!read_uleb128(&unit, &column))
					goto next;
				break;
			case DW_LNS_negate_stmt:
				is_stmt = !is_stmt;
				break;
			case DW_LNS_set_basic_block:
				basic_block = true;
				break;
			case DW_LNS_const_add_pc:
				address += (255 - opcode_base) / line_range;
				break;
			case DW_LNS_set_prologue_end:
				prologue_end = true;
				break;
			case DW_LNS_set_epilogue_begin:
				epilogue_begin = true;
				break;
			default:
				DWARN("unknown standard opcode: %d", opcode);
				goto next;
			}
		}

		if (emit) {
			if (address > pc) {
				/* Found an entry after our target PC. */
				if (!have_last) {
					/* Give up on this program. */
					break;
				}
				/* Return the last entry. */
				*outline = last_line;
				return (read_filename(&names, outdirname,
				    outbasename, opcode_base, file));
			}

			last_file = file;
			last_line = line;
			have_last = true;
		}

		if (reset_basic_block)
			basic_block = false;
	}

	goto next;
}
Esempio n. 25
0
_Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
		      _Unwind_Action actions,
		      _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED,
		      struct _Unwind_Exception *ue_header,
		      struct _Unwind_Context *context)
/* APPLE LOCAL begin LLVM */
#endif
/* APPLE LOCAL end LLVM */
{
  lsda_header_info info;
  const unsigned char *language_specific_data, *p, *action_record;
  _Unwind_Ptr landing_pad, ip;

/* APPLE LOCAL begin LLVM */
#ifdef __ARM_EABI_UNWINDER__
  if (state != _US_UNWIND_FRAME_STARTING)
    CONTINUE_UNWINDING;

  /* The dwarf unwinder assumes the context structure holds things like the
     function and LSDA pointers.  The ARM implementation caches these in
     the exception header (UCB).  To avoid rewriting everything we make the
     virtual IP register point at the UCB.  */
  ip = (_Unwind_Ptr) ue_header;
  _Unwind_SetGR (context, 12, ip);
#else
/* APPLE LOCAL end LLVM */
  if (version != 1)
    return _URC_FATAL_PHASE1_ERROR;

  /* Currently we only support cleanups for C.  */
  if ((actions & _UA_CLEANUP_PHASE) == 0)
/* APPLE LOCAL begin LLVM */
    CONTINUE_UNWINDING;
#endif
/* APPLE LOCAL end LLVM */

  language_specific_data = (const unsigned char *)
    _Unwind_GetLanguageSpecificData (context);

  /* If no LSDA, then there are no handlers or cleanups.  */
  if (! language_specific_data)
/* APPLE LOCAL begin LLVM */
    CONTINUE_UNWINDING;
/* APPLE LOCAL end LLVM */

  /* Parse the LSDA header.  */
  p = parse_lsda_header (context, language_specific_data, &info);
  ip = _Unwind_GetIP (context) - 1;
  landing_pad = 0;

#ifdef __USING_SJLJ_EXCEPTIONS__
  /* The given "IP" is an index into the call-site table, with two
     exceptions -- -1 means no-action, and 0 means terminate.  But
     since we're using uleb128 values, we've not got random access
     to the array.  */
  if ((int) ip <= 0)
    return _URC_CONTINUE_UNWIND;
  else
    {
      _Unwind_Word cs_lp, cs_action;
      do
	{
	  p = read_uleb128 (p, &cs_lp);
	  p = read_uleb128 (p, &cs_action);
	}
      while (--ip);

      /* Can never have null landing pad for sjlj -- that would have
	 been indicated by a -1 call site index.  */
      landing_pad = cs_lp + 1;
      if (cs_action)
	action_record = info.action_table + cs_action - 1;
      goto found_something;
    }
#else
  /* Search the call-site table for the action associated with this IP.  */
  while (p < info.action_table)
    {
      _Unwind_Ptr cs_start, cs_len, cs_lp;
      _Unwind_Word cs_action;

      /* Note that all call-site encodings are "absolute" displacements.  */
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
      p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
      p = read_uleb128 (p, &cs_action);

      /* The table is sorted, so if we've passed the ip, stop.  */
      if (ip < info.Start + cs_start)
	p = info.action_table;
      else if (ip < info.Start + cs_start + cs_len)
	{
	  if (cs_lp)
	    landing_pad = info.LPStart + cs_lp;
	  if (cs_action)
	    action_record = info.action_table + cs_action - 1;
	  goto found_something;
	}
    }
#endif

  /* IP is not in table.  No associated cleanups.  */
  /* ??? This is where C++ calls std::terminate to catch throw
     from a destructor.  */
/* APPLE LOCAL begin LLVM */
  CONTINUE_UNWINDING;
/* APPLE LOCAL end LLVM */

 found_something:
  if (landing_pad == 0)
    {
      /* IP is present, but has a null landing pad.
	 No handler to be run.  */
/* APPLE LOCAL begin LLVM */
      CONTINUE_UNWINDING;
/* APPLE LOCAL end LLVM */
    }

  _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
		 (_Unwind_Ptr) ue_header);
  _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
  _Unwind_SetIP (context, landing_pad);
  return _URC_INSTALL_CONTEXT;
}
static void
execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
		     struct frame_info *next_frame,
		     struct dwarf2_frame_state *fs)
{
  CORE_ADDR pc = frame_pc_unwind (next_frame);
  int bytes_read;

  while (insn_ptr < insn_end && fs->pc <= pc)
    {
      unsigned char insn = *insn_ptr++;
      ULONGEST utmp, reg;
      LONGEST offset;

      if ((insn & 0xc0) == DW_CFA_advance_loc)
	fs->pc += (insn & 0x3f) * fs->code_align;
      else if ((insn & 0xc0) == DW_CFA_offset)
	{
	  reg = insn & 0x3f;
	  insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
	  offset = utmp * fs->data_align;
	  dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	  fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
	  fs->regs.reg[reg].loc.offset = offset;
	}
      else if ((insn & 0xc0) == DW_CFA_restore)
	{
	  gdb_assert (fs->initial.reg);
	  reg = insn & 0x3f;
	  dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	  fs->regs.reg[reg] = fs->initial.reg[reg];
	}
      else
	{
	  switch (insn)
	    {
	    case DW_CFA_set_loc:
	      fs->pc = dwarf2_read_address (insn_ptr, insn_end, &bytes_read);
	      insn_ptr += bytes_read;
	      break;

	    case DW_CFA_advance_loc1:
	      utmp = extract_unsigned_integer (insn_ptr, 1);
	      fs->pc += utmp * fs->code_align;
	      insn_ptr++;
	      break;
	    case DW_CFA_advance_loc2:
	      utmp = extract_unsigned_integer (insn_ptr, 2);
	      fs->pc += utmp * fs->code_align;
	      insn_ptr += 2;
	      break;
	    case DW_CFA_advance_loc4:
	      utmp = extract_unsigned_integer (insn_ptr, 4);
	      fs->pc += utmp * fs->code_align;
	      insn_ptr += 4;
	      break;

	    case DW_CFA_offset_extended:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
	      offset = utmp * fs->data_align;
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
	      fs->regs.reg[reg].loc.offset = offset;
	      break;

	    case DW_CFA_restore_extended:
	      gdb_assert (fs->initial.reg);
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      fs->regs.reg[reg] = fs->initial.reg[reg];
	      break;

	    case DW_CFA_undefined:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED;
	      break;

	    case DW_CFA_same_value:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE;
	      break;

	    case DW_CFA_register:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
	      fs->regs.reg[reg].loc.reg = utmp;
	      break;

	    case DW_CFA_remember_state:
	      {
		struct dwarf2_frame_state_reg_info *new_rs;

		new_rs = XMALLOC (struct dwarf2_frame_state_reg_info);
		*new_rs = fs->regs;
		fs->regs.reg = dwarf2_frame_state_copy_regs (&fs->regs);
		fs->regs.prev = new_rs;
	      }
	      break;

	    case DW_CFA_restore_state:
	      {
		struct dwarf2_frame_state_reg_info *old_rs = fs->regs.prev;

		gdb_assert (old_rs);

		xfree (fs->regs.reg);
		fs->regs = *old_rs;
		xfree (old_rs);
	      }
	      break;

	    case DW_CFA_def_cfa:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
	      fs->cfa_offset = utmp;
	      fs->cfa_how = CFA_REG_OFFSET;
	      break;

	    case DW_CFA_def_cfa_register:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
	      fs->cfa_how = CFA_REG_OFFSET;
	      break;

	    case DW_CFA_def_cfa_offset:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_offset);
	      /* cfa_how deliberately not set.  */
	      break;

	    case DW_CFA_nop:
	      break;

	    case DW_CFA_def_cfa_expression:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_exp_len);
	      fs->cfa_exp = insn_ptr;
	      fs->cfa_how = CFA_EXP;
	      insn_ptr += fs->cfa_exp_len;
	      break;

	    case DW_CFA_expression:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
	      fs->regs.reg[reg].loc.exp = insn_ptr;
	      fs->regs.reg[reg].exp_len = utmp;
	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_EXP;
	      insn_ptr += utmp;
	      break;

	    case DW_CFA_offset_extended_sf:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
	      insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
	      offset += fs->data_align;
	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
	      fs->regs.reg[reg].loc.offset = offset;
	      break;

	    case DW_CFA_def_cfa_sf:
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
	      insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
	      fs->cfa_offset = offset * fs->data_align;
	      fs->cfa_how = CFA_REG_OFFSET;
	      break;

	    case DW_CFA_def_cfa_offset_sf:
	      insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
	      fs->cfa_offset = offset * fs->data_align;
	      /* cfa_how deliberately not set.  */
	      break;

	    case DW_CFA_GNU_args_size:
	      /* Ignored.  */
	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
	      break;

	    default:
	      internal_error (__FILE__, __LINE__, "Unknown CFI encountered.");
	    }
	}
    }

  /* Don't allow remember/restore between CIE and FDE programs.  */
  dwarf2_frame_state_free_regs (fs->regs.prev);
  fs->regs.prev = NULL;
}
Esempio n. 27
0
bfd_boolean
_bfd_elf_discard_section_eh_frame
   (bfd *abfd, struct bfd_link_info *info, asection *sec,
    bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *),
    struct elf_reloc_cookie *cookie)
{
#define REQUIRE(COND)					\
  do							\
    if (!(COND))					\
      goto free_no_table;				\
  while (0)

  bfd_byte *ehbuf = NULL, *buf;
  bfd_byte *last_fde;
  struct eh_cie_fde *ent, *this_inf;
  unsigned int hdr_length, hdr_id;
  struct extended_cie
    {
      struct cie cie;
      unsigned int offset;
      unsigned int usage_count;
      unsigned int entry;
    } *ecies = NULL, *ecie;
  unsigned int ecie_count = 0, ecie_alloced = 0;
  struct cie *cie;
  struct elf_link_hash_table *htab;
  struct eh_frame_hdr_info *hdr_info;
  struct eh_frame_sec_info *sec_info = NULL;
  unsigned int offset;
  unsigned int ptr_size;
  unsigned int entry_alloced;

  if (sec->size == 0)
    {
      /* This file does not contain .eh_frame information.  */
      return FALSE;
    }

  if (bfd_is_abs_section (sec->output_section))
    {
      /* At least one of the sections is being discarded from the
	 link, so we should just ignore them.  */
      return FALSE;
    }

  htab = elf_hash_table (info);
  hdr_info = &htab->eh_info;

  if (hdr_info->cies == NULL && !info->relocatable)
    hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free);

  /* Read the frame unwind information from abfd.  */

  REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf));

  if (sec->size >= 4
      && bfd_get_32 (abfd, ehbuf) == 0
      && cookie->rel == cookie->relend)
    {
      /* Empty .eh_frame section.  */
      free (ehbuf);
      return FALSE;
    }

  /* If .eh_frame section size doesn't fit into int, we cannot handle
     it (it would need to use 64-bit .eh_frame format anyway).  */
  REQUIRE (sec->size == (unsigned int) sec->size);

  ptr_size = (get_elf_backend_data (abfd)
	      ->elf_backend_eh_frame_address_size (abfd, sec));
  REQUIRE (ptr_size != 0);

  buf = ehbuf;
  sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info)
			  + 99 * sizeof (struct eh_cie_fde));
  REQUIRE (sec_info);

  entry_alloced = 100;

#define ENSURE_NO_RELOCS(buf)				\
  REQUIRE (!(cookie->rel < cookie->relend		\
	     && (cookie->rel->r_offset			\
		 < (bfd_size_type) ((buf) - ehbuf))	\
	     && cookie->rel->r_info != 0))

#define SKIP_RELOCS(buf)				\
  while (cookie->rel < cookie->relend			\
	 && (cookie->rel->r_offset			\
	     < (bfd_size_type) ((buf) - ehbuf)))	\
    cookie->rel++

#define GET_RELOC(buf)					\
  ((cookie->rel < cookie->relend			\
    && (cookie->rel->r_offset				\
	== (bfd_size_type) ((buf) - ehbuf)))		\
   ? cookie->rel : NULL)

  for (;;)
    {
      char *aug;
      bfd_byte *start, *end, *insns, *insns_end;
      bfd_size_type length;
      unsigned int set_loc_count;

      if (sec_info->count == entry_alloced)
	{
	  sec_info = bfd_realloc (sec_info,
				  sizeof (struct eh_frame_sec_info)
				  + ((entry_alloced + 99)
				     * sizeof (struct eh_cie_fde)));
	  REQUIRE (sec_info);

	  memset (&sec_info->entry[entry_alloced], 0,
		  100 * sizeof (struct eh_cie_fde));
	  entry_alloced += 100;
	}

      this_inf = sec_info->entry + sec_info->count;
      last_fde = buf;

      if ((bfd_size_type) (buf - ehbuf) == sec->size)
	break;

      /* Read the length of the entry.  */
      REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4));
      hdr_length = bfd_get_32 (abfd, buf - 4);

      /* 64-bit .eh_frame is not supported.  */
      REQUIRE (hdr_length != 0xffffffff);

      /* The CIE/FDE must be fully contained in this input section.  */
      REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size);
      end = buf + hdr_length;

      this_inf->offset = last_fde - ehbuf;
      this_inf->size = 4 + hdr_length;

      if (hdr_length == 0)
	{
	  /* A zero-length CIE should only be found at the end of
	     the section.  */
	  REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size);
	  ENSURE_NO_RELOCS (buf);
	  sec_info->count++;
	  break;
	}

      REQUIRE (skip_bytes (&buf, end, 4));
      hdr_id = bfd_get_32 (abfd, buf - 4);

      if (hdr_id == 0)
	{
	  unsigned int initial_insn_length;

	  /* CIE  */
	  this_inf->cie = 1;

	  if (ecie_count == ecie_alloced)
	    {
	      ecies = bfd_realloc (ecies,
				   (ecie_alloced + 20) * sizeof (*ecies));
	      REQUIRE (ecies);
	      memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies));
	      ecie_alloced += 20;
	    }

	  cie = &ecies[ecie_count].cie;
	  ecies[ecie_count].offset = this_inf->offset;
	  ecies[ecie_count++].entry = sec_info->count;
	  cie->length = hdr_length;
	  start = buf;
	  REQUIRE (read_byte (&buf, end, &cie->version));

	  /* Cannot handle unknown versions.  */
	  REQUIRE (cie->version == 1 || cie->version == 3);
	  REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation));

	  strcpy (cie->augmentation, (char *) buf);
	  buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1;
	  ENSURE_NO_RELOCS (buf);
	  if (buf[0] == 'e' && buf[1] == 'h')
	    {
	      /* GCC < 3.0 .eh_frame CIE */
	      /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__
		 is private to each CIE, so we don't need it for anything.
		 Just skip it.  */
	      REQUIRE (skip_bytes (&buf, end, ptr_size));
	      SKIP_RELOCS (buf);
	    }
	  REQUIRE (read_uleb128 (&buf, end, &cie->code_align));
	  REQUIRE (read_sleb128 (&buf, end, &cie->data_align));
	  if (cie->version == 1)
	    {
	      REQUIRE (buf < end);
	      cie->ra_column = *buf++;
	    }
	  else
	    REQUIRE (read_uleb128 (&buf, end, &cie->ra_column));
	  ENSURE_NO_RELOCS (buf);
	  cie->lsda_encoding = DW_EH_PE_omit;
	  cie->fde_encoding = DW_EH_PE_omit;
	  cie->per_encoding = DW_EH_PE_omit;
	  aug = cie->augmentation;
	  if (aug[0] != 'e' || aug[1] != 'h')
	    {
	      if (*aug == 'z')
		{
		  aug++;
		  REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size));
	  	  ENSURE_NO_RELOCS (buf);
		}

	      while (*aug != '\0')
		switch (*aug++)
		  {
		  case 'L':
		    REQUIRE (read_byte (&buf, end, &cie->lsda_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size));
		    break;
		  case 'R':
		    REQUIRE (read_byte (&buf, end, &cie->fde_encoding));
		    ENSURE_NO_RELOCS (buf);
		    REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size));
		    break;
		  case 'S':
		    break;
		  case 'P':
		    {
		      int per_width;

		      REQUIRE (read_byte (&buf, end, &cie->per_encoding));
		      per_width = get_DW_EH_PE_width (cie->per_encoding,
						      ptr_size);
		      REQUIRE (per_width);
		      if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned)
			{
			  length = -(buf - ehbuf) & (per_width - 1);
			  REQUIRE (skip_bytes (&buf, end, length));
			}
		      ENSURE_NO_RELOCS (buf);
		      /* Ensure we have a reloc here.  */
		      if (GET_RELOC (buf) != NULL)
			{
			  unsigned long r_symndx;

#ifdef BFD64
			  if (ptr_size == 8)
			    r_symndx = ELF64_R_SYM (cookie->rel->r_info);
			  else
#endif
			    r_symndx = ELF32_R_SYM (cookie->rel->r_info);
			  if (r_symndx >= cookie->locsymcount
			      || ELF_ST_BIND (cookie->locsyms[r_symndx]
					      .st_info) != STB_LOCAL)
			    {
			      struct elf_link_hash_entry *h;

			      r_symndx -= cookie->extsymoff;
			      h = cookie->sym_hashes[r_symndx];

			      while (h->root.type == bfd_link_hash_indirect
				     || h->root.type == bfd_link_hash_warning)
				h = (struct elf_link_hash_entry *)
				    h->root.u.i.link;

			      cie->personality.h = h;
			    }
			  else
			    {
			      Elf_Internal_Sym *sym;
			      asection *sym_sec;
			      bfd_vma val;

			      sym = &cookie->locsyms[r_symndx];
			      sym_sec = (bfd_section_from_elf_index
					 (abfd, sym->st_shndx));
			      if (sym_sec != NULL)
				{
				  if (sym_sec->kept_section != NULL)
				    sym_sec = sym_sec->kept_section;
				  if (sym_sec->output_section != NULL)
				    {
				      val = (sym->st_value
					     + sym_sec->output_offset
					     + sym_sec->output_section->vma);
				      cie->personality.val = val;
				      cie->local_personality = 1;
				    }
				}
			    }

			  /* Cope with MIPS-style composite relocations.  */
			  do
			    cookie->rel++;
			  while (GET_RELOC (buf) != NULL);
			}
		      REQUIRE (skip_bytes (&buf, end, per_width));
		      REQUIRE (cie->local_personality || cie->personality.h);
		    }
		    break;
		  default:
		    /* Unrecognized augmentation. Better bail out.  */
		    goto free_no_table;
		  }
	    }

	  /* For shared libraries, try to get rid of as many RELATIVE relocs
	     as possible.  */
	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_relative_eh_frame
		  (abfd, info, sec)))
	    {
	      if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr)
		cie->make_relative = 1;
	      /* If the CIE doesn't already have an 'R' entry, it's fairly
		 easy to add one, provided that there's no aligned data
		 after the augmentation string.  */
	      else if (cie->fde_encoding == DW_EH_PE_omit
		       && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned)
		{
		  if (*cie->augmentation == 0)
		    this_inf->add_augmentation_size = 1;
		  this_inf->add_fde_encoding = 1;
		  cie->make_relative = 1;
		}
	    }

	  if (info->shared
	      && (get_elf_backend_data (abfd)
		  ->elf_backend_can_make_lsda_relative_eh_frame
		  (abfd, info, sec))
	      && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr)
	    cie->make_lsda_relative = 1;

	  /* If FDE encoding was not specified, it defaults to
	     DW_EH_absptr.  */
	  if (cie->fde_encoding == DW_EH_PE_omit)
	    cie->fde_encoding = DW_EH_PE_absptr;

	  initial_insn_length = end - buf;
	  if (initial_insn_length <= sizeof (cie->initial_instructions))
	    {
	      cie->initial_insn_length = initial_insn_length;
	      memcpy (cie->initial_instructions, buf, initial_insn_length);
	    }
	  insns = buf;
	  buf += initial_insn_length;
	  ENSURE_NO_RELOCS (buf);
	}
      else
	{
	  /* Find the corresponding CIE.  */
	  unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
	  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
	    if (cie_offset == ecie->offset)
	      break;

	  /* Ensure this FDE references one of the CIEs in this input
	     section.  */
	  REQUIRE (ecie != ecies + ecie_count);
	  cie = &ecie->cie;

	  ENSURE_NO_RELOCS (buf);
	  REQUIRE (GET_RELOC (buf));

	  if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie))
	    /* This is a FDE against a discarded section.  It should
	       be deleted.  */
	    this_inf->removed = 1;
	  else
	    {
	      if (info->shared
		  && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr
		       && cie->make_relative == 0)
		      || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned))
		{
		  /* If a shared library uses absolute pointers
		     which we cannot turn into PC relative,
		     don't create the binary search table,
		     since it is affected by runtime relocations.  */
		  hdr_info->table = FALSE;
		  (*info->callbacks->einfo)
		    (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr"
		       " table being created.\n"), abfd, sec);
		}
	      ecie->usage_count++;
	      hdr_info->fde_count++;
	      this_inf->cie_inf = (void *) (ecie - ecies);
	    }

	  /* Skip the initial location and address range.  */
	  start = buf;
	  length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
	  REQUIRE (skip_bytes (&buf, end, 2 * length));

	  /* Skip the augmentation size, if present.  */
	  if (cie->augmentation[0] == 'z')
	    REQUIRE (read_uleb128 (&buf, end, &length));
	  else
	    length = 0;

	  /* Of the supported augmentation characters above, only 'L'
	     adds augmentation data to the FDE.  This code would need to
	     be adjusted if any future augmentations do the same thing.  */
	  if (cie->lsda_encoding != DW_EH_PE_omit)
	    {
	      this_inf->lsda_offset = buf - start;
	      /* If there's no 'z' augmentation, we don't know where the
		 CFA insns begin.  Assume no padding.  */
	      if (cie->augmentation[0] != 'z')
		length = end - buf;
	    }

	  /* Skip over the augmentation data.  */
	  REQUIRE (skip_bytes (&buf, end, length));
	  insns = buf;

	  buf = last_fde + 4 + hdr_length;
	  SKIP_RELOCS (buf);
	}

      /* Try to interpret the CFA instructions and find the first
	 padding nop.  Shrink this_inf's size so that it doesn't
	 include the padding.  */
      length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
      set_loc_count = 0;
      insns_end = skip_non_nops (insns, end, length, &set_loc_count);
      /* If we don't understand the CFA instructions, we can't know
	 what needs to be adjusted there.  */
      if (insns_end == NULL
	  /* For the time being we don't support DW_CFA_set_loc in
	     CIE instructions.  */
	  || (set_loc_count && this_inf->cie))
	goto free_no_table;
      this_inf->size -= end - insns_end;
      if (insns_end != end && this_inf->cie)
	{
	  cie->initial_insn_length -= end - insns_end;
	  cie->length -= end - insns_end;
	}
      if (set_loc_count
	  && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel
	      || cie->make_relative))
	{
	  unsigned int cnt;
	  bfd_byte *p;

	  this_inf->set_loc = bfd_malloc ((set_loc_count + 1)
					  * sizeof (unsigned int));
	  REQUIRE (this_inf->set_loc);
	  this_inf->set_loc[0] = set_loc_count;
	  p = insns;
	  cnt = 0;
	  while (p < end)
	    {
	      if (*p == DW_CFA_set_loc)
		this_inf->set_loc[++cnt] = p + 1 - start;
	      REQUIRE (skip_cfa_op (&p, end, length));
	    }
	}

      this_inf->fde_encoding = cie->fde_encoding;
      this_inf->lsda_encoding = cie->lsda_encoding;
      sec_info->count++;
    }

  elf_section_data (sec)->sec_info = sec_info;
  sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME;

  /* Look at all CIEs in this section and determine which can be
     removed as unused, which can be merged with previous duplicate
     CIEs and which need to be kept.  */
  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
    {
      if (ecie->usage_count == 0)
	{
	  sec_info->entry[ecie->entry].removed = 1;
	  continue;
	}
      ecie->cie.output_sec = sec->output_section;
      ecie->cie.cie_inf = sec_info->entry + ecie->entry;
      cie_compute_hash (&ecie->cie);
      if (hdr_info->cies != NULL)
	{
	  void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie,
						 ecie->cie.hash, INSERT);
	  if (loc != NULL)
	    {
	      if (*loc != HTAB_EMPTY_ENTRY)
		{
		  sec_info->entry[ecie->entry].removed = 1;
		  ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf;
		  continue;
		}

	      *loc = malloc (sizeof (struct cie));
	      if (*loc == NULL)
		*loc = HTAB_DELETED_ENTRY;
	      else
		memcpy (*loc, &ecie->cie, sizeof (struct cie));
	    }
	}
      ecie->cie.cie_inf->make_relative = ecie->cie.make_relative;
      ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative;
      ecie->cie.cie_inf->per_encoding_relative
	= (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel;
    }

  /* Ok, now we can assign new offsets.  */
  offset = 0;
  for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
    if (!ent->removed)
      {
	if (!ent->cie)
	  {
	    ecie = ecies + (bfd_hostptr_t) ent->cie_inf;
	    ent->cie_inf = ecie->cie.cie_inf;
	  }
	ent->new_offset = offset;
	offset += size_of_output_cie_fde (ent, ptr_size);
      }

  /* Resize the sec as needed.  */
  sec->rawsize = sec->size;
  sec->size = offset;

  free (ehbuf);
  if (ecies)
    free (ecies);
  return offset != sec->rawsize;

free_no_table:
  (*info->callbacks->einfo)
    (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"),
     abfd, sec);
  if (ehbuf)
    free (ehbuf);
  if (sec_info)
    free (sec_info);
  if (ecies)
    free (ecies);
  hdr_info->table = FALSE;
  return FALSE;

#undef REQUIRE
}
Esempio n. 28
0
static uintptr_t read_encoded_ptr(const uint8_t** data, uint8_t encoding)
{
  const uint8_t* p = *data;

  if(encoding == DW_EH_PE_omit)
    return 0;

  // Base pointer.
  uintptr_t result;

  switch(encoding & 0x0F)
  {
    case DW_EH_PE_absptr:
      result = *((uintptr_t*)p);
      p += sizeof(uintptr_t);
      break;

    case DW_EH_PE_udata2:
      result = *((uint16_t*)p);
      p += sizeof(uint16_t);
      break;

    case DW_EH_PE_udata4:
      result = *((uint32_t*)p);
      p += sizeof(uint32_t);
      break;

#if __UINTPTR_MAX__ >= __UINT64_MAX__
    case DW_EH_PE_udata8:
      result = *((uint64_t*)p);
      p += sizeof(uint64_t);
      break;
#endif

    case DW_EH_PE_sdata2:
      result = *((int16_t*)p);
      p += sizeof(int16_t);
      break;

    case DW_EH_PE_sdata4:
      result = *((int32_t*)p);
      p += sizeof(int32_t);
      break;

#if __UINTPTR_MAX__ >= __UINT64_MAX__
    case DW_EH_PE_sdata8:
      result = *((int64_t*)p);
      p += sizeof(int64_t);
      break;
#endif

    case DW_EH_PE_sleb128:
      result = read_sleb128(&p);
      break;

    case DW_EH_PE_uleb128:
      result = read_uleb128(&p);
      break;

    default:
      abort();
      break;
  }

  *data = p;
  return result;
}
Esempio n. 29
0
static bfd_boolean
skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width)
{
  bfd_byte op;
  bfd_vma length;

  if (!read_byte (iter, end, &op))
    return FALSE;

  switch (op & 0xc0 ? op & 0xc0 : op)
    {
    case DW_CFA_nop:
    case DW_CFA_advance_loc:
    case DW_CFA_restore:
    case DW_CFA_remember_state:
    case DW_CFA_restore_state:
    case DW_CFA_GNU_window_save:
      /* No arguments.  */
      return TRUE;

    case DW_CFA_offset:
    case DW_CFA_restore_extended:
    case DW_CFA_undefined:
    case DW_CFA_same_value:
    case DW_CFA_def_cfa_register:
    case DW_CFA_def_cfa_offset:
    case DW_CFA_def_cfa_offset_sf:
    case DW_CFA_GNU_args_size:
      /* One leb128 argument.  */
      return skip_leb128 (iter, end);

    case DW_CFA_val_offset:
    case DW_CFA_val_offset_sf:
    case DW_CFA_offset_extended:
    case DW_CFA_register:
    case DW_CFA_def_cfa:
    case DW_CFA_offset_extended_sf:
    case DW_CFA_GNU_negative_offset_extended:
    case DW_CFA_def_cfa_sf:
      /* Two leb128 arguments.  */
      return (skip_leb128 (iter, end)
	      && skip_leb128 (iter, end));

    case DW_CFA_def_cfa_expression:
      /* A variable-length argument.  */
      return (read_uleb128 (iter, end, &length)
	      && skip_bytes (iter, end, length));

    case DW_CFA_expression:
    case DW_CFA_val_expression:
      /* A leb128 followed by a variable-length argument.  */
      return (skip_leb128 (iter, end)
	      && read_uleb128 (iter, end, &length)
	      && skip_bytes (iter, end, length));

    case DW_CFA_set_loc:
      return skip_bytes (iter, end, encoded_ptr_width);

    case DW_CFA_advance_loc1:
      return skip_bytes (iter, end, 1);

    case DW_CFA_advance_loc2:
      return skip_bytes (iter, end, 2);

    case DW_CFA_advance_loc4:
      return skip_bytes (iter, end, 4);

    case DW_CFA_MIPS_advance_loc8:
      return skip_bytes (iter, end, 8);

    default:
      return FALSE;
    }
}
Esempio n. 30
0
static void
execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr,
		  unsigned char *op_end)
{
  ctx->in_reg = 0;

  while (op_ptr < op_end)
    {
      enum dwarf_location_atom op = *op_ptr++;
      CORE_ADDR result;
      ULONGEST uoffset, reg;
      LONGEST offset;
      int bytes_read;

      switch (op)
	{
	case DW_OP_lit0:
	case DW_OP_lit1:
	case DW_OP_lit2:
	case DW_OP_lit3:
	case DW_OP_lit4:
	case DW_OP_lit5:
	case DW_OP_lit6:
	case DW_OP_lit7:
	case DW_OP_lit8:
	case DW_OP_lit9:
	case DW_OP_lit10:
	case DW_OP_lit11:
	case DW_OP_lit12:
	case DW_OP_lit13:
	case DW_OP_lit14:
	case DW_OP_lit15:
	case DW_OP_lit16:
	case DW_OP_lit17:
	case DW_OP_lit18:
	case DW_OP_lit19:
	case DW_OP_lit20:
	case DW_OP_lit21:
	case DW_OP_lit22:
	case DW_OP_lit23:
	case DW_OP_lit24:
	case DW_OP_lit25:
	case DW_OP_lit26:
	case DW_OP_lit27:
	case DW_OP_lit28:
	case DW_OP_lit29:
	case DW_OP_lit30:
	case DW_OP_lit31:
	  result = op - DW_OP_lit0;
	  break;

	case DW_OP_addr:
	  result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
	  op_ptr += bytes_read;
	  break;

	case DW_OP_const1u:
	  result = extract_unsigned_integer (op_ptr, 1);
	  op_ptr += 1;
	  break;
	case DW_OP_const1s:
	  result = extract_signed_integer (op_ptr, 1);
	  op_ptr += 1;
	  break;
	case DW_OP_const2u:
	  result = extract_unsigned_integer (op_ptr, 2);
	  op_ptr += 2;
	  break;
	case DW_OP_const2s:
	  result = extract_signed_integer (op_ptr, 2);
	  op_ptr += 2;
	  break;
	case DW_OP_const4u:
	  result = extract_unsigned_integer (op_ptr, 4);
	  op_ptr += 4;
	  break;
	case DW_OP_const4s:
	  result = extract_signed_integer (op_ptr, 4);
	  op_ptr += 4;
	  break;
	case DW_OP_const8u:
	  result = extract_unsigned_integer (op_ptr, 8);
	  op_ptr += 8;
	  break;
	case DW_OP_const8s:
	  result = extract_signed_integer (op_ptr, 8);
	  op_ptr += 8;
	  break;
	case DW_OP_constu:
	  op_ptr = read_uleb128 (op_ptr, op_end, &uoffset);
	  result = uoffset;
	  break;
	case DW_OP_consts:
	  op_ptr = read_sleb128 (op_ptr, op_end, &offset);
	  result = offset;
	  break;

	/* The DW_OP_reg operations are required to occur alone in
	   location expressions.  */
	case DW_OP_reg0:
	case DW_OP_reg1:
	case DW_OP_reg2:
	case DW_OP_reg3:
	case DW_OP_reg4:
	case DW_OP_reg5:
	case DW_OP_reg6:
	case DW_OP_reg7:
	case DW_OP_reg8:
	case DW_OP_reg9:
	case DW_OP_reg10:
	case DW_OP_reg11:
	case DW_OP_reg12:
	case DW_OP_reg13:
	case DW_OP_reg14:
	case DW_OP_reg15:
	case DW_OP_reg16:
	case DW_OP_reg17:
	case DW_OP_reg18:
	case DW_OP_reg19:
	case DW_OP_reg20:
	case DW_OP_reg21:
	case DW_OP_reg22:
	case DW_OP_reg23:
	case DW_OP_reg24:
	case DW_OP_reg25:
	case DW_OP_reg26:
	case DW_OP_reg27:
	case DW_OP_reg28:
	case DW_OP_reg29:
	case DW_OP_reg30:
	case DW_OP_reg31:
	  if (op_ptr != op_end && *op_ptr != DW_OP_piece)
	    error ("DWARF-2 expression error: DW_OP_reg operations must be "
		   "used either alone or in conjuction with DW_OP_piece.");

	  result = op - DW_OP_reg0;
	  ctx->in_reg = 1;

	  break;

	case DW_OP_regx:
	  op_ptr = read_uleb128 (op_ptr, op_end, &reg);
	  if (op_ptr != op_end && *op_ptr != DW_OP_piece)
	    error ("DWARF-2 expression error: DW_OP_reg operations must be "
		   "used either alone or in conjuction with DW_OP_piece.");

	  result = reg;
	  ctx->in_reg = 1;
	  break;

	case DW_OP_breg0:
	case DW_OP_breg1:
	case DW_OP_breg2:
	case DW_OP_breg3:
	case DW_OP_breg4:
	case DW_OP_breg5:
	case DW_OP_breg6:
	case DW_OP_breg7:
	case DW_OP_breg8:
	case DW_OP_breg9:
	case DW_OP_breg10:
	case DW_OP_breg11:
	case DW_OP_breg12:
	case DW_OP_breg13:
	case DW_OP_breg14:
	case DW_OP_breg15:
	case DW_OP_breg16:
	case DW_OP_breg17:
	case DW_OP_breg18:
	case DW_OP_breg19:
	case DW_OP_breg20:
	case DW_OP_breg21:
	case DW_OP_breg22:
	case DW_OP_breg23:
	case DW_OP_breg24:
	case DW_OP_breg25:
	case DW_OP_breg26:
	case DW_OP_breg27:
	case DW_OP_breg28:
	case DW_OP_breg29:
	case DW_OP_breg30:
	case DW_OP_breg31:
	  {
	    op_ptr = read_sleb128 (op_ptr, op_end, &offset);
	    result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0);
	    result += offset;
	  }
	  break;
	case DW_OP_bregx:
	  {
	    op_ptr = read_uleb128 (op_ptr, op_end, &reg);
	    op_ptr = read_sleb128 (op_ptr, op_end, &offset);
	    result = (ctx->read_reg) (ctx->baton, reg);
	    result += offset;
	  }
	  break;
	case DW_OP_fbreg:
	  {
	    unsigned char *datastart;
	    size_t datalen;
	    unsigned int before_stack_len;

	    op_ptr = read_sleb128 (op_ptr, op_end, &offset);
	    /* Rather than create a whole new context, we simply
	       record the stack length before execution, then reset it
	       afterwards, effectively erasing whatever the recursive
	       call put there.  */
	    before_stack_len = ctx->stack_len;
	    /* FIXME: cagney/2003-03-26: This code should be using
               get_frame_base_address(), and then implement a dwarf2
               specific this_base method.  */
	    (ctx->get_frame_base) (ctx->baton, &datastart, &datalen);
	    dwarf_expr_eval (ctx, datastart, datalen);
	    result = dwarf_expr_fetch (ctx, 0);
	    if (ctx->in_reg)
	      result = (ctx->read_reg) (ctx->baton, result);
	    result = result + offset;
	    ctx->stack_len = before_stack_len;
	    ctx->in_reg = 0;
	  }
	  break;
	case DW_OP_dup:
	  result = dwarf_expr_fetch (ctx, 0);
	  break;

	case DW_OP_drop:
	  dwarf_expr_pop (ctx);
	  goto no_push;

	case DW_OP_pick:
	  offset = *op_ptr++;
	  result = dwarf_expr_fetch (ctx, offset);
	  break;

	case DW_OP_over:
	  result = dwarf_expr_fetch (ctx, 1);
	  break;

	case DW_OP_rot:
	  {
	    CORE_ADDR t1, t2, t3;

	    if (ctx->stack_len < 3)
	       error ("Not enough elements for DW_OP_rot. Need 3, have %d\n",
		      ctx->stack_len);
	    t1 = ctx->stack[ctx->stack_len - 1];
	    t2 = ctx->stack[ctx->stack_len - 2];
	    t3 = ctx->stack[ctx->stack_len - 3];
	    ctx->stack[ctx->stack_len - 1] = t2;
	    ctx->stack[ctx->stack_len - 2] = t3;
	    ctx->stack[ctx->stack_len - 3] = t1;
	    goto no_push;
	  }

	case DW_OP_deref:
	case DW_OP_deref_size:
	case DW_OP_abs:
	case DW_OP_neg:
	case DW_OP_not:
	case DW_OP_plus_uconst:
	  /* Unary operations.  */
	  result = dwarf_expr_fetch (ctx, 0);
	  dwarf_expr_pop (ctx);

	  switch (op)
	    {
	    case DW_OP_deref:
	      {
		char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
		int bytes_read;

		(ctx->read_mem) (ctx->baton, buf, result,
				 TARGET_ADDR_BIT / TARGET_CHAR_BIT);
		result = dwarf2_read_address (buf,
					      buf + (TARGET_ADDR_BIT
						     / TARGET_CHAR_BIT),
					      &bytes_read);
	      }
	      break;

	    case DW_OP_deref_size:
	      {
		char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
		int bytes_read;

		(ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
		result = dwarf2_read_address (buf,
					      buf + (TARGET_ADDR_BIT
						     / TARGET_CHAR_BIT),
					      &bytes_read);
	      }
	      break;

	    case DW_OP_abs:
	      if ((signed int) result < 0)
		result = -result;
	      break;
	    case DW_OP_neg:
	      result = -result;
	      break;
	    case DW_OP_not:
	      result = ~result;
	      break;
	    case DW_OP_plus_uconst:
	      op_ptr = read_uleb128 (op_ptr, op_end, &reg);
	      result += reg;
	      break;
	    }
	  break;

	case DW_OP_and:
	case DW_OP_div:
	case DW_OP_minus:
	case DW_OP_mod:
	case DW_OP_mul:
	case DW_OP_or:
	case DW_OP_plus:
	case DW_OP_shl:
	case DW_OP_shr:
	case DW_OP_shra:
	case DW_OP_xor:
	case DW_OP_le:
	case DW_OP_ge:
	case DW_OP_eq:
	case DW_OP_lt:
	case DW_OP_gt:
	case DW_OP_ne:
	  {
	    /* Binary operations.  Use the value engine to do computations in
	       the right width.  */
	    CORE_ADDR first, second;
	    enum exp_opcode binop;
	    struct value *val1, *val2;

	    second = dwarf_expr_fetch (ctx, 0);
	    dwarf_expr_pop (ctx);

	    first = dwarf_expr_fetch (ctx, 0);
	    dwarf_expr_pop (ctx);

	    val1 = value_from_longest (unsigned_address_type (), first);
	    val2 = value_from_longest (unsigned_address_type (), second);

	    switch (op)
	      {
	      case DW_OP_and:
		binop = BINOP_BITWISE_AND;
		break;
	      case DW_OP_div:
		binop = BINOP_DIV;
                break;
	      case DW_OP_minus:
		binop = BINOP_SUB;
		break;
	      case DW_OP_mod:
		binop = BINOP_MOD;
		break;
	      case DW_OP_mul:
		binop = BINOP_MUL;
		break;
	      case DW_OP_or:
		binop = BINOP_BITWISE_IOR;
		break;
	      case DW_OP_plus:
		binop = BINOP_ADD;
		break;
	      case DW_OP_shl:
		binop = BINOP_LSH;
		break;
	      case DW_OP_shr:
		binop = BINOP_RSH;
                break;
	      case DW_OP_shra:
		binop = BINOP_RSH;
		val1 = value_from_longest (signed_address_type (), first);
		break;
	      case DW_OP_xor:
		binop = BINOP_BITWISE_XOR;
		break;
	      case DW_OP_le:
		binop = BINOP_LEQ;
		break;
	      case DW_OP_ge:
		binop = BINOP_GEQ;
		break;
	      case DW_OP_eq:
		binop = BINOP_EQUAL;
		break;
	      case DW_OP_lt:
		binop = BINOP_LESS;
		break;
	      case DW_OP_gt:
		binop = BINOP_GTR;
		break;
	      case DW_OP_ne:
		binop = BINOP_NOTEQUAL;
		break;
	      default:
		internal_error (__FILE__, __LINE__,
				"Can't be reached.");
	      }
	    result = value_as_long (value_binop (val1, val2, binop));
	  }
	  break;

	case DW_OP_GNU_push_tls_address:
	  /* Variable is at a constant offset in the thread-local
	  storage block into the objfile for the current thread and
	  the dynamic linker module containing this expression. Here
	  we return returns the offset from that base.  The top of the
	  stack has the offset from the beginning of the thread
	  control block at which the variable is located.  Nothing
	  should follow this operator, so the top of stack would be
	  returned.  */
	  result = dwarf_expr_fetch (ctx, 0);
	  dwarf_expr_pop (ctx);
	  result = (ctx->get_tls_address) (ctx->baton, result);
	  break;

	case DW_OP_skip:
	  offset = extract_signed_integer (op_ptr, 2);
	  op_ptr += 2;
	  op_ptr += offset;
	  goto no_push;

	case DW_OP_bra:
	  offset = extract_signed_integer (op_ptr, 2);
	  op_ptr += 2;
	  if (dwarf_expr_fetch (ctx, 0) != 0)
	    op_ptr += offset;
	  dwarf_expr_pop (ctx);
	  goto no_push;

	case DW_OP_nop:
	  goto no_push;

        case DW_OP_piece:
          {
            ULONGEST size;
            CORE_ADDR addr_or_regnum;

            /* Record the piece.  */
            op_ptr = read_uleb128 (op_ptr, op_end, &size);
            addr_or_regnum = dwarf_expr_fetch (ctx, 0);
            add_piece (ctx, ctx->in_reg, addr_or_regnum, size);

            /* Pop off the address/regnum, and clear the in_reg flag.  */
            dwarf_expr_pop (ctx);
            ctx->in_reg = 0;
          }
          goto no_push;

	default:
	  error ("Unhandled dwarf expression opcode 0x%x", op);
	}

      /* Most things push a result value.  */
      dwarf_expr_push (ctx, result);
    no_push:;
    }
}