Exemple #1
0
/* Return the path contained in the .gnu_debuglink section or NULL if we cannot
 * find it.
 *
 * XXX: There's also a CRC in here that we could use to warn if the files are
 * out of sync.
 */
const char *
drsym_obj_debuglink_section(void *mod_in)
{
    elf_info_t *mod = (elf_info_t *) mod_in;
    Elf_Shdr *section_header =
        elf_getshdr(find_elf_section_by_name(mod->elf, ".gnu_debuglink"));
    if (section_header == NULL) {
        NOTIFY_ELF();
        return NULL;
    }
    return ((char*) mod->map_base) + section_header->sh_offset;
}
Exemple #2
0
/*
  returns the *internal* offset of __start. (that's what
  the symbol table contains in any case)
  The absolute address is different, offset by the .vma field of the .text
  section (where __start resides)
  returns -1 on error
*/
long get_start_addr (Elf * elf)
{
    const char STARTSYM[] = "__start";

    Elf_Scn
	*temp_scn = NULL;
    
    Elf32_Shdr * shdr;

    size_t shstrndx;		/* not too sure what this means */

    if (elf_getshstrndx(elf, &shstrndx) == 0) {
	fprintf (stderr, "getshstrndx() failed: %s\n",
		 elf_errmsg(-1));
	goto error_egress;
    }

    /* iterate over the headers. */
    while ( (temp_scn = elf_nextscn(elf, temp_scn)) != NULL) {

	shdr = elf_getshdr (temp_scn);

	if (shdr == NULL) {
	    fprintf (stderr, "elf_getshdr() failed: %s\n",
		     elf_errmsg(-1));
	    goto error_egress;
	}

	if ( (name = elf_strptr(elf, shstrndx, shdr.sh_name) ) == NULL) {
	    fprintf (stderr, "elf_strptr() failed: %s\n",
		     elf_errmsg(-1));
	    goto error_egress;
	}

	if (strncmp (STARTSYM, name, sizeof(STARTSYM)) != 0) {
	    /* wrong name */
	    continue;
	}

	/* We got it! */
	
	
    }

 error_egress:
    
}
Exemple #3
0
void *
drsym_obj_mod_init_pre(byte *map_base, size_t file_size)
{
    elf_info_t *mod;
    Elf_Scn *symtab_scn;
    Elf_Scn *strtab_scn;
    Elf_Shdr *symtab_shdr;

    mod = dr_global_alloc(sizeof(*mod));
    memset(mod, 0, sizeof(*mod));
    mod->map_base = map_base;

    mod->elf = elf_memory((char *)map_base, file_size);

    symtab_scn = find_elf_section_by_name(mod->elf, ".symtab");
    strtab_scn = find_elf_section_by_name(mod->elf, ".strtab");

    if (symtab_scn != NULL) {
        mod->debug_kind |= DRSYM_SYMBOLS | DRSYM_ELF_SYMTAB;

        if (strtab_scn != NULL) {
            symtab_shdr = elf_getshdr(symtab_scn);
            mod->strtab_idx = elf_ndxscn(strtab_scn);
            mod->num_syms = symtab_shdr->sh_size / symtab_shdr->sh_entsize;

            /* This assumes that the ELF file uses the same representation conventions
             * as the current machine, which is reasonable considering this module is
             * probably loaded in the current process.
             */
            mod->syms = (Elf_Sym*)(((char*) mod->map_base) + symtab_shdr->sh_offset);
        }
    } else {
        /* XXX i#672: there may still be dwarf2 or stabs sections even if the
         * symtable is stripped and we could do symbol lookup via dwarf2
         */
    }

    if (find_elf_section_by_name(mod->elf, ".debug_line") != NULL) {
        mod->debug_kind |= DRSYM_LINE_NUMS | DRSYM_DWARF_LINE;
    }

    return (void *) mod;
}
Exemple #4
0
/* Looks for a section with real data, not just a section with a header */
static Elf_Scn *
find_elf_section_by_name(Elf *elf, const char *match_name)
{
    Elf_Scn *scn;
    size_t shstrndx;  /* Means "section header string table section index" */

    if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
        NOTIFY_ELF();
        return NULL;
    }

    for (scn = elf_getscn(elf, 0); scn != NULL; scn = elf_nextscn(elf, scn)) {
        Elf_Shdr *section_header = elf_getshdr(scn);
        const char *sec_name;
        if (section_header == NULL) {
            NOTIFY_ELF();
            continue;
        }
        sec_name = elf_strptr(elf, shstrndx, section_header->sh_name);
        if (sec_name == NULL) {
            NOTIFY_ELF();
        }
        if (strcmp(sec_name, match_name) == 0) {
            /* For our purposes, we want to treat a no-data section
             * type as if it didn't exist.  This happens sometimes in
             * debuglink files where some sections like .symtab are
             * present b/c the headers mirror the original ELF file, but
             * there's no data there.  Xref i#642.
             */
            if (TEST(SHT_NOBITS, section_header->sh_type))
                return NULL;
            return scn;
        }
    }
    return NULL;
}
Exemple #5
0
/*
 * Archive members are typically extracted to resolve an existing undefined
 * reference.  However, other symbol definitions can cause archive members to
 * be processed to determine if the archive member provides a more appropriate
 * definition.  This routine processes the archive member to determine if the
 * member is really required.
 *
 *  i.	Tentative symbols may cause the extraction of an archive member.
 *	If the archive member has a strong defined symbol it will be used.
 *	If the archive member simply contains another tentative definition,
 *	or a defined function symbol, then it will not be used.
 *
 *  ii.	A symbol reference may define a hidden or protected visibility.  The
 *	reference can only be bound to a definition within a relocatable object
 *	for this restricted visibility to be satisfied.  If the archive member
 * 	provides a definition of the same symbol type, this definition is
 *	taken.  The visibility of the defined symbol is irrelevant, as the most
 *	restrictive visibility of the reference and the definition will be
 *	applied to the final symbol.
 *
 * exit:
 *	Returns 1 if there is a match, 0 if no match is seen, and S_ERROR if an
 *	error occurred.
 */
static uintptr_t
process_member(Ar_mem *amp, const char *name, Sym_desc *sdp, Ofl_desc *ofl)
{
	Sym	*syms, *osym = sdp->sd_sym;
	Xword	symn, cnt;
	char 	*strs;

	/*
	 * Find the first symbol table in the archive member, obtain its
	 * data buffer and determine the number of global symbols (Note,
	 * there must be a symbol table present otherwise the archive would
	 * never have been able to generate its own symbol entry for this
	 * member).
	 */
	if (amp->am_syms == NULL) {
		Elf_Scn		*scn = NULL;
		Shdr		*shdr;
		Elf_Data	*data;

		while (scn = elf_nextscn(amp->am_elf, scn)) {
			if ((shdr = elf_getshdr(scn)) == NULL) {
				ld_eprintf(ofl, ERR_ELF,
				    MSG_INTL(MSG_ELF_GETSHDR), amp->am_path);
				return (S_ERROR);
			}
			if ((shdr->sh_type == SHT_SYMTAB) ||
			    (shdr->sh_type == SHT_DYNSYM))
				break;
		}
		if ((data = elf_getdata(scn, NULL)) == NULL) {
			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETDATA),
			    amp->am_path);
			return (S_ERROR);
		}
		syms = (Sym *)data->d_buf;
		syms += shdr->sh_info;
		symn = shdr->sh_size / shdr->sh_entsize;
		symn -= shdr->sh_info;

		/*
		 * Get the data for the associated string table.
		 */
		if ((scn = elf_getscn(amp->am_elf, (size_t)shdr->sh_link)) ==
		    NULL) {
			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETSCN),
			    amp->am_path);
			return (S_ERROR);
		}
		if ((data = elf_getdata(scn, NULL)) == NULL) {
			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETDATA),
			    amp->am_path);
			return (S_ERROR);
		}
		strs = data->d_buf;

		/*
		 * Initialize the archive member structure in case we have to
		 * come through here again.
		 */
		amp->am_syms = syms;
		amp->am_strs = strs;
		amp->am_symn = symn;
	} else {
		syms = amp->am_syms;
		strs = amp->am_strs;
		symn = amp->am_symn;
	}

	/*
	 * Loop through the symbol table entries looking for a match for the
	 * original symbol.
	 */
	for (cnt = 0; cnt < symn; syms++, cnt++) {
		Word	shndx;

		if ((shndx = syms->st_shndx) == SHN_UNDEF)
			continue;

		if (osym->st_shndx == SHN_COMMON) {
			/*
			 * Determine whether a tentative symbol definition
			 * should be overridden.
			 */
			if ((shndx == SHN_ABS) || (shndx == SHN_COMMON) ||
			    (ELF_ST_TYPE(syms->st_info) == STT_FUNC))
				continue;

			/*
			 * A historic detail requires that a weak definition
			 * within an archive will not override a strong
			 * definition (see sym_realtent() resolution and ABI
			 * symbol binding description - page 4-27).
			 */
			if ((ELF_ST_BIND(syms->st_info) == STB_WEAK) &&
			    (ELF_ST_BIND(osym->st_info) != STB_WEAK))
				continue;
		} else {
			/*
			 * Determine whether a restricted visibility reference
			 * should be overridden.  Don't worry about the
			 * visibility of the archive member definition, nor
			 * whether it is weak or global.  Any definition is
			 * better than a binding to an external shared object
			 * (which is the only event that must presently exist
			 * for us to be here looking for a better alternative).
			 */
			if (ELF_ST_TYPE(syms->st_info) !=
			    ELF_ST_TYPE(osym->st_info))
				continue;
		}

		if (strcmp(strs + syms->st_name, name) == 0)
			return (1);
	}
	return (0);
}
Exemple #6
0
int main()
{
    Dwarf_Error error = 0;
    Dwarf_P_Debug dw = dwarf_producer_init_c(DW_DLC_WRITE | DW_DLC_SIZE_64,
                       createSectionCallback,
                       /* error handler */0,
                       /* error arg */0,
                       /* user data */0,
                       &error);
    if (error != 0)
        die("dwarf_producer_init_c failed");

    Dwarf_Unsigned cie = dwarf_add_frame_cie(dw,
                         "",
                         /* code alignment factor */QT_POINTER_SIZE,
                         /* data alignment factor */-QT_POINTER_SIZE,
                         /* return address reg*/InstructionPointerRegister,
                         cie_init_instructions,
                         sizeof(cie_init_instructions),
                         &error);
    if (error != 0)
        die("dwarf_add_frame_cie failed");

    Dwarf_P_Fde fde = dwarf_new_fde(dw, &error);
    if (error != 0)
        die("dwarf_new_fde failed");

    /* New entry in state machine for code offset 1 after push rbp instruction */
    dwarf_add_fde_inst(fde,
                       DW_CFA_advance_loc,
                       /*offset in code alignment units*/ 1,
                       /* unused*/ 0,
                       &error);

    /* After "push rbp" the offset to the CFA is now 2 instead of 1 */
    dwarf_add_fde_inst(fde,
                       DW_CFA_def_cfa_offset_sf,
                       /*offset in code alignment units*/ -2,
                       /* unused*/ 0,
                       &error);

    /* After "push rbp" the value of rbp is now stored at offset 1 from CFA */
    dwarf_add_fde_inst(fde,
                       DW_CFA_offset,
                       StackFrameRegister,
                       2,
                       &error);

    /* New entry in state machine for code offset 3 for mov rbp, rsp instruction */
    dwarf_add_fde_inst(fde,
                       DW_CFA_advance_loc,
                       /*offset in code alignment units*/ 3,
                       /* unused */ 0,
                       &error);

    /* After "mov rbp, rsp" the cfa is reachable via rbp */
    dwarf_add_fde_inst(fde,
                       DW_CFA_def_cfa_register,
                       StackFrameRegister,
                       /* unused */0,
                       &error);

    /* Callee saved registers */
    for (int i = 0; i < calleeSavedRegisterCount; ++i) {
        dwarf_add_fde_inst(fde,
                           DW_CFA_offset,
                           calleeSavedRegisters[i],
                           i + 3,
                           &error);
    }

    dwarf_add_frame_fde(dw, fde,
                        /* die */0,
                        cie,
                        /*virt addr */0,
                        /* length of code */0,
                        /* symbol index */0,
                        &error);
    if (error != 0)
        die("dwarf_add_frame_fde failed");

    dwarf_transform_to_disk_form(dw, &error);
    if (error != 0)
        die("dwarf_transform_to_disk_form failed");

    Dwarf_Unsigned len = 0;
    Dwarf_Signed elfIdx = 0;
    unsigned char *bytes = (unsigned char *)dwarf_get_section_bytes(dw, /* section */1,
                           &elfIdx, &len, &error);
    if (error != 0)
        die("dwarf_get_section_bytes failed");

    // libdwarf doesn't add a terminating FDE with zero length, so let's add one
    // ourselves.
    unsigned char *newBytes = (unsigned char *)alloca(len + 4);
    memcpy(newBytes, bytes, len);
    newBytes[len] = 0;
    newBytes[len + 1] = 0;
    newBytes[len + 2] = 0;
    newBytes[len + 3] = 0;
    newBytes[len + 4] = 0;
    bytes = newBytes;
    len += 4;

    // Reset CIE-ID back to 0 as expected for .eh_frames
    bytes[4] = 0;
    bytes[5] = 0;
    bytes[6] = 0;
    bytes[7] = 0;

    unsigned fde_offset = bytes[0] + 4;

    bytes[fde_offset + 4] = fde_offset + 4;

    printf("static const unsigned char cie_fde_data[] = {\n");
    int i = 0;
    while (i < len) {
        printf("    ");
        for (int j = 0; i < len && j < 8; ++j, ++i)
            printf("0x%x, ", bytes[i]);
        printf("\n");
    }
    printf("};\n");

    printf("static const int fde_offset = %d;\n", fde_offset);
    printf("static const int initial_location_offset = %d;\n", fde_offset + 8);
    printf("static const int address_range_offset = %d;\n", fde_offset + 8 + QT_POINTER_SIZE);

#ifdef DEBUG
    {
        if (elf_version(EV_CURRENT) == EV_NONE)
            die("wrong elf version");
        int fd = open("debug.o", O_WRONLY | O_CREAT, 0777);
        if (fd < 0)
            die("cannot create debug.o");

        Elf *e = elf_begin(fd, ELF_C_WRITE, 0);
        if (!e)
            die("elf_begin failed");

        Elf_Ehdr *ehdr = elf_newehdr(e);
        if (!ehdr)
            die(elf_errmsg(-1));

        ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
#if defined(Q_PROCESSOR_X86_64)
        ehdr->e_machine = EM_X86_64;
#elif defined(Q_PROCESSOR_X86)
        ehdr->e_machine = EM_386;
#else
#error port me :)
#endif
        ehdr->e_type = ET_EXEC;
        ehdr->e_version = EV_CURRENT;

        Elf_Scn *section = elf_newscn(e);
        if (!section)
            die("elf_newscn failed");

        Elf_Data *data = elf_newdata(section);
        if (!data)
            die(elf_errmsg(-1));
        data->d_align = 4;
        data->d_off = 0;
        data->d_buf = bytes;
        data->d_size = len;
        data->d_type = ELF_T_BYTE;
        data->d_version = EV_CURRENT;

        Elf_Shdr *shdr = elf_getshdr(section);
        if (!shdr)
            die(elf_errmsg(-1));

        shdr->sh_name = 1;
        shdr->sh_type = SHT_PROGBITS;
        shdr->sh_entsize = 0;

        char stringTable[] = {
            0,
            '.', 'e', 'h', '_', 'f', 'r', 'a', 'm', 'e', 0,
            '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0
        };

        section = elf_newscn(e);
        if (!section)
            die("elf_newscn failed");

        data = elf_newdata(section);
        if (!data)
            die(elf_errmsg(-1));
        data->d_align = 1;
        data->d_off = 0;
        data->d_buf = stringTable;
        data->d_size = sizeof(stringTable);
        data->d_type = ELF_T_BYTE;
        data->d_version = EV_CURRENT;

        shdr = elf_getshdr(section);
        if (!shdr)
            die(elf_errmsg(-1));

        shdr->sh_name = 11;
        shdr->sh_type = SHT_STRTAB;
        shdr->sh_flags = SHF_STRINGS | SHF_ALLOC;
        shdr->sh_entsize = 0;

        ehdr->e_shstrndx = elf_ndxscn(section);

        if (elf_update(e, ELF_C_WRITE) < 0)
            die(elf_errmsg(-1));

        elf_end(e);
        close(fd);
    }
#endif

    dwarf_producer_finish(dw, &error);
    if (error != 0)
        die("dwarf_producer_finish failed");
    return 0;
}
Exemple #7
0
int
symtab_init(void)
{
	Elf		*elf;
	Elf_Scn		*scn = NULL;
	Sym		*symtab, *symp, *lastsym;
	char		*strtab;
	uint_t		cnt;
	int		fd;
	int		i;
	int		strindex = -1;

	if ((fd = open("/dev/ksyms", O_RDONLY)) == -1)
		return (-1);

	(void) elf_version(EV_CURRENT);

	elf = elf_begin(fd, ELF_C_READ, NULL);

	for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {
		Shdr *shdr = elf_getshdr(scn);
		if (shdr->sh_type == SHT_SYMTAB) {
			symtab = (Sym *)elf_getdata(scn, NULL)->d_buf;
			nsyms = shdr->sh_size / shdr->sh_entsize;
			strindex = shdr->sh_link;
		}
	}

	for (cnt = 1; (scn = elf_nextscn(elf, scn)) != NULL; cnt++) {
		if (cnt == strindex)
			strtab = (char *)elf_getdata(scn, NULL)->d_buf;
	}

	lastsym = symtab + nsyms;
	nsyms = 0;
	for (symp = symtab; symp < lastsym; symp++)
		if ((uint_t)ELF32_ST_TYPE(symp->st_info) <= STT_FUNC &&
		    symp->st_size != 0)
			add_symbol(symp->st_name + strtab,
			    (uintptr_t)symp->st_value, (size_t)symp->st_size);

	fake_up_certain_popular_kernel_symbols();
	(void) sprintf(maxsymname, "0x%lx", ULONG_MAX);
	add_symbol(maxsymname, ULONG_MAX, 1);

	qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);

	/*
	 * Destroy all duplicate symbols, then sort it again.
	 */
	for (i = 0; i < nsyms - 1; i++)
		if (symbol_table[i].addr == symbol_table[i + 1].addr)
			symbol_table[i].addr = 0;

	qsort(symbol_table, nsyms, sizeof (syment_t), symcmp);

	while (symbol_table[1].addr == 0) {
		symbol_table++;
		nsyms--;
	}
	symbol_table[0].name = "(usermode)";
	symbol_table[0].addr = 0;
	symbol_table[0].size = 1;

	return (0);
}