8000 dwarves/libctf.c at master · acmel/dwarves · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
775 lines (650 loc) · 17.9 KB

libctf.c

File metadata and controls

775 lines (650 loc) · 17.9 KB
__func__, *size, bf_size, z.total_out, z.total_in);
#endif
} while (z.total_in != *size);
if (deflate(&z, Z_FINISH) == Z_STREAM_ERROR)
goto out_close_and_free;
deflateEnd(&z);
*size = z.total_out;
out:
return bf;
out_close_and_free:
deflateEnd(&z);
free(bf);
bf = NULL;
goto out;
}
int ctf__encode(struct ctf *ctf, uint8_t flags)
{
struct ctf_header *hdr;
unsigned int size;
void *bf = NULL;
int err = -1;
/* Empty file, nothing to do, so... done! */
if (gobuffer__size(&ctf->types) == 0)
return 0;
size = (gobuffer__size(&ctf->types) +
gobuffer__size(&ctf->objects) +
gobuffer__size(&ctf->funcs) +
strings__size(ctf->strings));
ctf->size = sizeof(*hdr) + size;
ctf->buf = malloc(ctf->size);
if (ctf->buf == NULL) {
fprintf(stderr, "%s: malloc failed!\n", __func__);
return -ENOMEM;
}
hdr = ctf->buf;
memset(hdr, 0, sizeof(*hdr));
hdr->ctf_magic = CTF_MAGIC;
hdr->ctf_version = 2;
hdr->ctf_flags = flags;
uint32_t offset = 0;
hdr->ctf_object_off = offset;
offset += gobuffer__size(&ctf->objects);
hdr->ctf_func_off = offset;
offset += gobuffer__size(&ctf->funcs);
hdr->ctf_type_off = offset;
offset += gobuffer__size(&ctf->types);
hdr->ctf_str_off = offset;
hdr->ctf_str_len = strings__size(ctf->strings);
void *payload = ctf->buf + sizeof(*hdr);
gobuffer__copy(&ctf->objects, payload + hdr->ctf_object_off);
gobuffer__copy(&ctf->funcs, payload + hdr->ctf_func_off);
gobuffer__copy(&ctf->types, payload + hdr->ctf_type_off);
strings__copy(ctf->strings, payload + hdr->ctf_str_off);
*(char *)(ctf->buf + sizeof(*hdr) + hdr->ctf_str_off) = '\0';
if (flags & CTF_FLAGS_COMPR) {
bf = (void *)ctf__compress(ctf->buf + sizeof(*hdr), &size);
if (bf == NULL) {
printf("%s: ctf__compress failed!\n", __func__);
return -ENOMEM;
}
void *new_bf = malloc(sizeof(*hdr) + size);
if (new_bf == NULL)
return -ENOMEM;
memcpy(new_bf, hdr, sizeof(*hdr));
memcpy(new_bf + sizeof(*hdr), bf, size);
free(bf);
bf = new_bf;
size += sizeof(*hdr);
} else {
bf = ctf->buf;
size = ctf->size;
}
#if 0
printf("\n\ntypes:\n entries: %d\n size: %u"
"\nstrings:\n size: %u\ncompressed size: %d\n",
ctf->type_index,
gobuffer__size(&ctf->types),
strings__size(ctf->strings), size);
#endif
int fd = open(ctf->filename, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Cannot open %s\n", ctf->filename);
return -1;
}
if (elf_version(EV_CURRENT) == EV_NONE) {
fprintf(stderr, "Cannot set libelf version.\n");
goto out_close;
}
Elf *elf = elf_begin(fd, ELF_C_RDWR, NULL);
if (elf == NULL) {
fprintf(stderr, "Cannot update ELF file.\n");
goto out_close;
}
elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY);
GElf_Ehdr ehdr_mem;
GElf_Ehdr *ehdr = gelf_getehdr(elf, &ehdr_mem);
if (ehdr == NULL) {
fprintf(stderr, "%s: elf_getehdr failed.\n", __func__);
goto out_close;
}
/*
* First we look if there was already a .SUNW_ctf section to overwrite.
*/
Elf_Data *data = NULL;
size_t strndx;
GElf_Shdr shdr_mem;
GElf_Shdr *shdr;
Elf_Scn *scn = NULL;
elf_getshdrstrndx(elf, &strndx);
while ((scn = elf_nextscn(elf, scn)) != NULL) {
shdr = gelf_getshdr(scn, &shdr_mem);
if (shdr == NULL)
continue;
char *secname = elf_strptr(elf, strndx, shdr->sh_name);
if (secname != NULL && strcmp(secname, ".SUNW_ctf") == 0) {
data = elf_getdata(scn, data);
goto out_update;
}
}
/* FIXME
* OK, if we have the section, that is ok, we can just replace the
* data, if not, I made a mistake on the small amount of boilerplate
* below, probably .relA.ted to relocations...
*/
#if 0
/* Now we look if the ".SUNW_ctf" string is in the strings table */
scn = elf_getscn(elf, strndx);
shdr = gelf_getshdr(scn, &shdr_mem);
data = elf_getdata(scn, data);
fprintf(stderr, "Looking for the string\n");
size_t ctf_name_offset = 1; /* First byte is '\0' */
while (ctf_name_offset < data->d_size) {
const char *cur_str = data->d_buf + ctf_name_offset;
fprintf(stderr, "*-> %s\n", cur_str);
if (strcmp(cur_str, ".SUNW_ctf") == 0)
goto found_SUNW_ctf_str;
ctf_name_offset += strlen(cur_str) + 1;
}
/* Add the section name */
const size_t ctf_name_len = strlen(".SUNW_ctf") + 1;
char *new_strings_table = malloc(data->d_size + ctf_name_len);
if (new_strings_table == NULL)
goto out_close;
memcpy(new_strings_table, data->d_buf, data->d_size);
strcpy(new_strings_table + data->d_size, ".SUNW_ctf");
ctf_name_offset = data->d_size;
data->d_size += ctf_name_len;
data->d_buf = new_strings_table;
elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
Elf_Scn *newscn;
found_SUNW_ctf_str:
newscn = elf_newscn(elf);
if (newscn == NULL)
goto out_close;
data = elf_newdata(newscn);
if (data == NULL)
goto out_close;
shdr = gelf_getshdr(newscn, &shdr_mem);
shdr->sh_name = ctf_name_offset;
shdr->sh_type = SHT_PROGBITS;
gelf_update_shdr(newscn, &shdr_mem);
elf_flagshdr(newscn, ELF_C_SET, ELF_F_DIRTY);
#else
char pathname[PATH_MAX];
snprintf(pathname, sizeof(pathname), "%s.SUNW_ctf", ctf->filename);
fd = creat(pathname, S_IRUSR | S_IWUSR);
if (fd == -1) {
fprintf(stderr, "%s: open(%s) failed!\n", __func__, pathname);
goto out_close;
}
if (write(fd, bf, size) != size)
goto out_close;
if (close(fd) < 0)
goto out_unlink;
char add_section[PATH_MAX + 32];
snprintf(add_section, sizeof(add_section), ".SUNW_ctf=%s", pathname);
if (exec_objcopy("objcopy", add_section, ctf->filename) == 0)
err = 0;
out_unlink:
unlink(pathname);
return err;
#endif
out_update:
data->d_buf = bf;
data->d_size = size;
elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
if (elf_update(elf, ELF_C_NULL) < 0)
goto out_close;
if (elf_update(elf, ELF_C_WRITE) < 0)
goto out_close;
elf_end(elf);
err = 0;
out_close:
if (bf != ctf->buf)
free(bf);
close(fd);
return err;
}
#endif
0