コード例 #1
0
ファイル: dwarf_parse.c プロジェクト: andre-werner/argentum
int
dwarf_rip_debug_info(uintptr_t rip, struct Rip_debug_info *info)
{
    // these symbols are defined in core/core.ld
    extern uint8_t _debug_aranges_begin[], _debug_aranges_end[];
    
    info->file_name = "<unknown>";
    info->fn_name = "<unknown>";
    info->fn_offset = 0;
    
    if (_debug_aranges_end <= _debug_aranges_begin)
        // no debugging info?
        return -1;

    // Search the table of address ranges for the instruction pointer
    uint8_t *p = _debug_aranges_begin; 
    while (p < _debug_aranges_end) {
        // read the header
        uint32_t length = extract_uint(p, 4, &p);
        uint8_t *e = p + length;
        extract_uint(p, 2, &p); // version
        uint32_t offset = extract_uint(p, 4, &p);
        extract_uint(p, 1, &p); // address size
        extract_uint(p, 1, &p); // segment size
        
        // the first touple begins at an offset that is a multiple of the size 
        // of a single tuple (i.e. twice the size of an address)
        p += 4;

        while (p < e) {
            uint64_t range_addr = extract_uint(p, 8, &p);
            uint64_t range_length = extract_uint(p, 8, &p);

            //kprintf("%p - %p\n", range_addr, range_addr + range_length);
        
            // each set of tuples is terminated by a 0 for the address and 0 
            // for the length
            if (range_addr == 0 && range_length == 0)
                break;

            if (rip >= range_addr && rip < (range_addr + range_length))
                // the instruction pointer belongs to this compile unit
                return parse_cu(pa2kva(offset), rip, info);
        }
    }
    return 0;
}
コード例 #2
0
ファイル: dwarf_parse.c プロジェクト: andre-werner/argentum
// Find the abbreviation declaration for the given code. Returns pointer to the
// declaration's tag.
// If you pass an invalid code, the behaviour is unpredicted! TODO: fix this
static uint8_t *
find_abbrev_decl(uint8_t *p, uint64_t code)
{
    for (;;) {
        uint64_t c = extract_uleb128(p, &p);
        if (c == code)
            return p;
        if (c == 0)
            continue;

        extract_uleb128(p, &p);
        extract_uint(p, 1, &p);

        for (;;) {
            uint64_t name = extract_uleb128(p, &p);
            uint64_t form = extract_uleb128(p, &p);
        
            if (name == 0 && form == 0)
                break;
        }
    }
}
コード例 #3
0
static void
write_int (st_parameter_dt *dtp, const fnode *f, const char *source, int len,
           const char *(*conv) (GFC_UINTEGER_LARGEST, char *, size_t))
{
  GFC_UINTEGER_LARGEST n = 0;
  int w, m, digits, nzero, nblank;
  char *p;
  const char *q;
  char itoa_buf[GFC_BTOA_BUF_SIZE];

  w = f->u.integer.w;
  m = f->u.integer.m;

  n = extract_uint (source, len);

  /* Special case:  */

  if (m == 0 && n == 0)
    {
      if (w == 0)
        w = 1;

      p = write_block (dtp, w);
      if (p == NULL)
        return;

      memset (p, ' ', w);
      goto done;
    }

  q = conv (n, itoa_buf, sizeof (itoa_buf));
  digits = strlen (q);

  /* Select a width if none was specified.  The idea here is to always
     print something.  */

  if (w == 0)
    w = ((digits < m) ? m : digits);

  p = write_block (dtp, w);
  if (p == NULL)
    return;

  nzero = 0;
  if (digits < m)
    nzero = m - digits;

  /* See if things will work.  */

  nblank = w - (nzero + digits);

  if (nblank < 0)
    {
      star_fill (p, w);
      goto done;
    }


  if (!dtp->u.p.no_leading_blank)
    {
      memset (p, ' ', nblank);
      p += nblank;
      memset (p, '0', nzero);
      p += nzero;
      memcpy (p, q, digits);
    }
  else
    {
      memset (p, '0', nzero);
      p += nzero;
      memcpy (p, q, digits);
      p += digits;
      memset (p, ' ', nblank);
      dtp->u.p.no_leading_blank = 0;
    }

 done:
  return;
}
コード例 #4
0
ファイル: nbsp2ldm.c プロジェクト: m4son/nbsp
int main(int argc, char **argv){
  
  char *optstr = "c:f:gmno:p:q:s:S:";
  char *usage = "nbsp2ldm [-c ccbsize] [-f feedtype] [-g] [-m] [-n]"
    " [-o origin] [-p prodid] [-q pqfname] [-s seq]"
    " <filename> | -S <filesize> < stdin";
  int status = 0;
  int c;

  while((status == 0) && ((c = getopt(argc, argv, optstr)) != -1)){
    switch(c){
    case 'c':
      status = extract_uint(optarg, &g.opt_ccbsize);
      if(status != 0)
	errx(1, "Invalid value for [-c].");

      break;
    case 'f':
      status = extract_uint(optarg, &g.opt_feedtype);
      if(status != 0)
	errx(1, "Invalid value for [-f].");

      break;
    case 'g':
      g.opt_gempak = 1;
      break;
    case 'm':
      g.opt_md5seq = 1;
      break;
    case 'n':
      g.opt_noccb = 1;
      break;
    case 'o':
      g.opt_origin = optarg;
      break;
    case 'p':
      g.opt_prodid = optarg;
      break;
    case 'q':
      g.opt_pqfname = optarg;
      break;
    case 's':
      g.opt_seq_str = optarg;
      status = extract_uint(optarg, &g.seq);
      if(status != 0)
	errx(1, "Invalid value for [-s].");

      break;
    case 'S':
      status = extract_uint(optarg, &g.opt_filesize);
      if(status != 0)
	errx(1, "Invalid value for [-S].");

      break;
    case 'h':
    default:
      status = 1;
      errx(1, usage);
      break;
    }
  }

  if(optind < argc - 1)
    errx(1, "Too many arguments.");
  else if(optind == argc - 1)
    g.input_fname = argv[optind++];
  else if((g.opt_filesize == 0) || (g.opt_prodid == NULL))
    errx(1, "Options [-S] and [-p] are mandatory when reading from stdin.");

  if(atexit(cleanup) != 0)
    err(1, "atexit");

  status = process_file();

  return(status != 0 ? 1 : 0);
}
コード例 #5
0
ファイル: nbsp2ldm.c プロジェクト: noaaport/nbsp
static void process_args(int argc, char **argv,
			 char *optstr, int f_set_defaults) {

  char *usage = "nbsp2ldm [OPTIONS] <filename> \n\
nbsp2ldm [OPTIONS] < stdin \n\
nbsp2ldm -S <filesize> [OPTIONS] < stdin \n\
OPTIONS = [-b] [-c ccbsize] [-f feedtype] [-g] [-m] [-n] \n\
          [-o origin] [-p prodid] [-q pqfname] [-s seq] [-v]";
  int status = 0;
  int c;

  /*
   * If (optind != 1) it means we are re-entering this function. In
   * FreeBSD optreset must be set to 1 before the second and each additional
   * set of calls to getopt(), and the variable optind must be reinitialized.
   */
  if(optind != 1){
    optreset = 1;
    optind = 1;
  }
  
  while((c = getopt(argc, argv, optstr)) != -1) {
    switch(c){
    case 'b':
      g.opt_background = 1;
      break;
    case 'c':
      status = extract_uint(optarg, &g.opt_ccbsize);
      if(status != 0)
	log_errx(1, "Invalid value for [-c].");

      if(f_set_defaults)
	gdefault.opt_ccbsize = g.opt_ccbsize;

      break;
    case 'd':
      g.opt_strsplit_delim = optarg;
      break;
    case 'f':
      status = extract_uint(optarg, &g.opt_feedtype);
      if(status != 0)
	log_errx(1, "Invalid value for [-f].");

      if(f_set_defaults)
	gdefault.opt_feedtype = g.opt_feedtype;

      break;
    case 'g':
      g.opt_gempak = 1;
      if(f_set_defaults)
	gdefault.opt_gempak = 1;

      break;
    case 'm':
      g.opt_md5seq = 1;
      if(f_set_defaults)
	gdefault.opt_md5seq = 1;

      break;
    case 'n':
      g.opt_noccb = 1;
      if(f_set_defaults)
	gdefault.opt_noccb = 1;

      break;
    case 'o':
      g.opt_origin = optarg;
      if(f_set_defaults)
	gdefault.opt_origin = optarg;

      break;
    case 'p':
      g.opt_prodid = optarg;
      break;
    case 'q':
      g.opt_pqfname = optarg;
      if(f_set_defaults)
	gdefault.opt_pqfname = optarg;

      break;
    case 's':
      g.opt_seq_str = optarg;
      status = extract_uint(optarg, &g.seq);
      if(status != 0)
	log_errx(1, "Invalid value for [-s].");

      break;
    case 'S':
      status = extract_uint(optarg, &g.opt_filesize);
      if(status != 0)
	log_errx(1, "Invalid value for [-S].");

      break;
    case 'v':
      g.opt_verbose = 1;
      if(f_set_defaults)
	gdefault.opt_verbose = 1;

      break;
    case 'h':
    default:
      status = 1;
      fprintf(stdout, "%s\n", usage);
      break;
    }
  }

  if(status != 0)
    exit(status);
}
コード例 #6
0
ファイル: dwarf_parse.c プロジェクト: andre-werner/argentum
// Parse the compile unit. Find the function to which the instruction pointer
// belongs and fill the info structure.
static int
parse_cu(uint8_t *p, uintptr_t rip, struct Rip_debug_info *info)
{
    // read the compile unit header
    uint32_t length = extract_uint(p, 4, &p);
    uint8_t *e = p + length;
    extract_uint(p, 2, &p); // version
    uint32_t abbr_offset = extract_uint(p, 4, &p);
    extract_uint(p, 1, &p); // address size

    while (p < e) {
        uint64_t code;

        // skip null DIEs
        do {
            code = extract_uleb128(p, &p);
        } while (code == 0 && p < e);
        if (p >= e)
            break;

        // Search the abbreviation table for the declaration with this code
        uint8_t *abbr = find_abbrev_decl(pa2kva(abbr_offset), code);
        uint64_t tag = extract_uleb128(abbr, &abbr);
        extract_uint(abbr, 1, &abbr);   // skip the has_children tag

        // read the attributes
        // we're interested only in several tags and attributes 
        uintptr_t fn_lo = 0, fn_hi = 0;
        char *fn_name = NULL;
        for (;;) {
            uint64_t name = extract_uleb128(abbr, &abbr);
            uint64_t form = extract_uleb128(abbr, &abbr);
            union Attr_val val;
            
            if (name == 0 && form == 0)
                break;
           
            // extract the attribute value
            if (extract_value(p, form, &val, &p) == -1)
                return -1;

            if (tag == DW_TAG_compile_unit && name == DW_AT_name) {
                info->file_name = val.string;
            } else if (tag == DW_TAG_subprogram) {
                if (name == DW_AT_name)
                    fn_name = val.string;
                else if (name == DW_AT_low_pc)
                    fn_lo = val.number;
                else if (name == DW_AT_high_pc)
                    fn_hi = val.number;
            }
        }

        if (tag == DW_TAG_subprogram) {
            // if the recently parsed tag was a function tag...
            if (rip >= fn_lo && rip <= fn_hi) {
                // ... and the instruction pointer belongs to this function
                if (fn_name)
                    info->fn_name = fn_name;
                info->fn_offset = rip - fn_lo;
            }
        }
    }
    return 0;
}
コード例 #7
0
ファイル: dwarf_parse.c プロジェクト: andre-werner/argentum
// Extract the attribute value of the given form
static int
extract_value(uint8_t *p, uint64_t form, union Attr_val *value, uint8_t **e)
{
    switch (form) {
    case DW_FORM_data1:
    case DW_FORM_ref1:
    case DW_FORM_flag:
        value->number = extract_uint(p, 1, &p);
        break;
    case DW_FORM_data2:
    case DW_FORM_ref2:
        value->number = extract_uint(p, 2, &p);
        break;
    case DW_FORM_data4:
    case DW_FORM_ref4:
        value->number = extract_uint(p, 4, &p);
        break;
    case DW_FORM_data8:
    case DW_FORM_ref8:
    case DW_FORM_addr:
    case DW_FORM_ref_addr:
        value->number = extract_uint(p, 8, &p);
        break;
    case DW_FORM_sdata:
        value->number = extract_sleb128(p, &p);
        break;
    case DW_FORM_udata:
    case DW_FORM_ref_udata:
        value->number = extract_uleb128(p, &p);
        break;
    case DW_FORM_string:
        value->string = (char *) p;
        while (*p++)
            ;
        break;
    case DW_FORM_strp:
        value->string = (char *) pa2kva(extract_uint(p, 4, &p));
        break;
    case DW_FORM_block1:
        value->block.length = extract_uint(p, 1, &p);
        value->block.data = (char *) p;
        p += value->block.length;
        break;
    case DW_FORM_block2:
        value->block.length = extract_uint(p, 2, &p);
        value->block.data = (char *) p;
        p += value->block.length;
        break;
    case DW_FORM_block4:
        value->block.length = extract_uint(p, 4, &p);
        value->block.data = (char *) p;
        p += value->block.length;
        break;
    case DW_FORM_block:
        value->block.length = extract_uleb128(p, &p);
        value->block.data = (char *) p;
        p += value->block.length;
        break;
    case DW_FORM_indirect:
        form = extract_uleb128(p, &p);
        return extract_value(p, form, value, &p);
    default:
        kprintf("uknown attribute form: %x\n", form);
        return -1;
    }
    if (e)
        *e = p;
    return 0;
}
コード例 #8
0
ファイル: unwind.c プロジェクト: AlainODea/illumos-gate
/*
 * Create an unwind header (.eh_frame_hdr) output section.
 * The section is created and space reserved, but the data
 * is not copied into place. That is done by a later call
 * to ld_unwind_populate(), after active relocations have been
 * processed.
 *
 * When GNU linkonce processing is in effect, we can end up in a situation
 * where the FDEs related to discarded sections remain in the eh_frame
 * section. Ideally, we would remove these dead entries from eh_frame.
 * However, that optimization has not yet been implemented. In the current
 * implementation, the number of dead FDEs cannot be determined until
 * active relocations are processed, and that processing follows the
 * call to this function. This means that we are unable to detect dead FDEs
 * here, and the section created by this routine is sized for maximum case
 * where all FDEs are valid.
 */
uintptr_t
ld_unwind_make_hdr(Ofl_desc *ofl)
{
	int		bswap = (ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0;
	Shdr		*shdr;
	Elf_Data	*elfdata;
	Is_desc		*isp;
	size_t		size;
	Xword		fde_cnt;
	Aliste		idx1;
	Os_desc		*osp;

	/*
	 * we only build a unwind header if we have
	 * some unwind information in the file.
	 */
	if (ofl->ofl_unwind == NULL)
		return (1);

	/*
	 * Allocate and initialize the Elf_Data structure.
	 */
	if ((elfdata = libld_calloc(sizeof (Elf_Data), 1)) == NULL)
		return (S_ERROR);
	elfdata->d_type = ELF_T_BYTE;
	elfdata->d_align = ld_targ.t_m.m_word_align;
	elfdata->d_version = ofl->ofl_dehdr->e_version;

	/*
	 * Allocate and initialize the Shdr structure.
	 */
	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == NULL)
		return (S_ERROR);
	shdr->sh_type = ld_targ.t_m.m_sht_unwind;
	shdr->sh_flags = SHF_ALLOC;
	shdr->sh_addralign = ld_targ.t_m.m_word_align;
	shdr->sh_entsize = 0;

	/*
	 * Allocate and initialize the Is_desc structure.
	 */
	if ((isp = libld_calloc(1, sizeof (Is_desc))) == NULL)
		return (S_ERROR);
	isp->is_name = MSG_ORIG(MSG_SCN_UNWINDHDR);
	isp->is_shdr = shdr;
	isp->is_indata = elfdata;

	if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp, NULL,
	    ld_targ.t_id.id_unwindhdr, NULL)) == (Os_desc *)S_ERROR)
		return (S_ERROR);

	/*
	 * Scan through all of the input Frame information, counting each FDE
	 * that requires an index.  Each fde_entry gets a corresponding entry
	 * in the binary search table.
	 */
	fde_cnt = 0;
	for (APLIST_TRAVERSE(ofl->ofl_unwind, idx1, osp)) {
		Aliste	idx2;
		int	os_isdescs_idx;

		OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx2, isp) {
			uchar_t		*data;
			uint64_t	off = 0;

			data = isp->is_indata->d_buf;
			size = isp->is_indata->d_size;

			while (off < size) {
				uint_t		length, id;
				uint64_t	ndx = 0;

				/*
				 * Extract length in lsb format.  A zero length
				 * indicates that this CIE is a terminator and
				 * that processing for unwind information is
				 * complete.
				 */
				length = extract_uint(data + off, &ndx, bswap);
				if (length == 0)
					break;

				/*
				 * Extract CIE id in lsb format.
				 */
				id = extract_uint(data + off, &ndx, bswap);

				/*
				 * A CIE record has a id of '0', otherwise
				 * this is a FDE entry and the 'id' is the
				 * CIE pointer.
				 */
				if (id == 0) {
					uint_t	cieversion;
					/*
					 * The only CIE version supported
					 * is '1' - quick sanity check
					 * here.
					 */
					cieversion = data[off + ndx];
					ndx += 1;
					/* BEGIN CSTYLED */
					if (cieversion != 1) {
					    ld_eprintf(ofl, ERR_FATAL,
						MSG_INTL(MSG_UNW_BADCIEVERS),
						isp->is_file->ifl_name,
						isp->is_name, off);
					    return (S_ERROR);
					}
					/* END CSTYLED */
				} else {
					fde_cnt++;
				}
				off += length + 4;
			}
		}
	}