int read_build_id(void *note_data, size_t note_len, void *bf, size_t size) { struct { u32 n_namesz; u32 n_descsz; u32 n_type; } *nhdr; void *ptr; printf("begin: sizeof(nhdr) = %d\n", sizeof(*nhdr)); ptr = note_data; while (ptr < (note_data + note_len)) { const char *name, *desc; size_t namesz, descsz; printf("ptr: 0x%X\n", (unsigned int)ptr); nhdr = ptr; namesz = NOTE_ALIGN(nhdr->n_namesz); descsz = NOTE_ALIGN(nhdr->n_descsz); printf("namesz: %u\ndescsz: %u\n", namesz, descsz); ptr += sizeof(*nhdr); name = ptr; printf("name: %s\n", name); ptr += namesz; desc = ptr; printf("desc: %s\n", desc); if (nhdr->n_type == 3 && nhdr->n_namesz == sizeof("GNU")) { if (memcmp(name, "GNU", sizeof("GNU")) == 0) { size_t sz = min(size, descsz); memcpy(bf, ptr, sz); memset(bf + sz, 0, size - sz); printf("found GNU!\n"); return 0; } } ptr += descsz; } return -1; }
static int read_build_id(void *note_data, size_t note_len, void *bf, size_t size, bool need_swap) { struct { u32 n_namesz; u32 n_descsz; u32 n_type; } *nhdr; void *ptr; ptr = note_data; while (ptr < (note_data + note_len)) { const char *name; size_t namesz, descsz; nhdr = ptr; if (need_swap) { nhdr->n_namesz = bswap_32(nhdr->n_namesz); nhdr->n_descsz = bswap_32(nhdr->n_descsz); nhdr->n_type = bswap_32(nhdr->n_type); } namesz = NOTE_ALIGN(nhdr->n_namesz); descsz = NOTE_ALIGN(nhdr->n_descsz); ptr += sizeof(*nhdr); name = ptr; ptr += namesz; if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == sizeof("GNU")) { if (memcmp(name, "GNU", sizeof("GNU")) == 0) { size_t sz = min(size, descsz); memcpy(bf, ptr, sz); memset(bf + sz, 0, size - sz); return 0; } } ptr += descsz; } return -1; }
size_t gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result, size_t *name_offset, size_t *desc_offset) { if (data == NULL) return 0; if (unlikely (data->d_type != ELF_T_NHDR)) { __libelf_seterrno (ELF_E_INVALID_HANDLE); return 0; } /* It's easy to handle this type. It has the same size for 32 and 64 bit objects. */ assert (sizeof (GElf_Nhdr) == sizeof (Elf32_Nhdr)); assert (sizeof (GElf_Nhdr) == sizeof (Elf64_Nhdr)); rwlock_rdlock (((Elf_Data_Scn *) data)->s->elf->lock); /* The data is already in the correct form. Just make sure the offset is OK. */ if (unlikely (offset > data->d_size || data->d_size - offset < sizeof (GElf_Nhdr))) { __libelf_seterrno (ELF_E_OFFSET_RANGE); offset = 0; } else { const GElf_Nhdr *n = data->d_buf + offset; offset += sizeof *n; /* Include padding. Check below for overflow. */ GElf_Word namesz = NOTE_ALIGN (n->n_namesz); GElf_Word descsz = NOTE_ALIGN (n->n_descsz); if (unlikely (offset > data->d_size || data->d_size - offset < namesz || (namesz == 0 && n->n_namesz != 0))) offset = 0; else { *name_offset = offset; offset += namesz; if (unlikely (offset > data->d_size || data->d_size - offset < descsz || (descsz == 0 && n->n_descsz != 0))) offset = 0; else { *desc_offset = offset; offset += descsz; *result = *n; } } } rwlock_unlock (((Elf_Data_Scn *) data)->s->elf->lock); return offset; }
static bool get_build_id( Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) { HdrType hdr; memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT); // First read the rest of the header. if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT, sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) { return false; } for (size_t i = 0; i < hdr.e_phnum; i++) { PhdrType phdr; if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize, reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) { return false; } // Looking for the .note.gnu.build-id note. if (phdr.p_type == PT_NOTE) { size_t hdr_size = phdr.p_filesz; uintptr_t addr = base_addr + phdr.p_offset; while (hdr_size >= sizeof(NhdrType)) { NhdrType nhdr; if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) { return false; } addr += sizeof(nhdr); if (nhdr.n_type == NT_GNU_BUILD_ID) { // Skip the name (which is the owner and should be "GNU"). addr += NOTE_ALIGN(nhdr.n_namesz); uint8_t build_id_data[128]; if (nhdr.n_namesz > sizeof(build_id_data)) { ALOGE("Possible corrupted note, name size value is too large: %u", nhdr.n_namesz); return false; } if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) { return false; } build_id->clear(); for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) { *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]); } return true; } else { // Move past the extra note data. hdr_size -= sizeof(nhdr); size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz); addr += skip_bytes; if (hdr_size < skip_bytes) { break; } hdr_size -= skip_bytes; } } } } return false; }