/** Converts 32-bit disk representation to host representation */ void SgAsmElfSectionTableEntry::ctor(ByteOrder sex, const Elf32SectionTableEntry_disk *disk) { p_sh_name = disk_to_host(sex, disk->sh_name); p_sh_type = (SectionType)disk_to_host(sex, disk->sh_type); p_sh_flags = disk_to_host(sex, disk->sh_flags); p_sh_addr = disk_to_host(sex, disk->sh_addr); p_sh_offset = disk_to_host(sex, disk->sh_offset); p_sh_size = disk_to_host(sex, disk->sh_size); p_sh_link = disk_to_host(sex, disk->sh_link); p_sh_info = disk_to_host(sex, disk->sh_info); p_sh_addralign = disk_to_host(sex, disk->sh_addralign); p_sh_entsize = disk_to_host(sex, disk->sh_entsize); }
/** Converts 32-bit disk representation to host representation */ void SgAsmElfSegmentTableEntry::ctor(ByteOrder sex, const struct Elf32SegmentTableEntry_disk *disk) { p_type = (SegmentType)disk_to_host(sex, disk->p_type); p_offset = disk_to_host(sex, disk->p_offset); p_vaddr = disk_to_host(sex, disk->p_vaddr); p_paddr = disk_to_host(sex, disk->p_paddr); p_filesz = disk_to_host(sex, disk->p_filesz); p_memsz = disk_to_host(sex, disk->p_memsz); p_flags = (SegmentFlags)disk_to_host(sex, disk->p_flags); p_align = disk_to_host(sex, disk->p_align); }
/** Initialize a note by parsing it from the specified location in the note section. Return value is the offset to the * beginning of the next note. */ rose_addr_t SgAsmElfNoteEntry::parse(rose_addr_t at) { /* Find the section holding this note */ SgAsmElfNoteSection *notes = SageInterface::getEnclosingNode<SgAsmElfNoteSection>(this); ROSE_ASSERT(notes!=NULL); ROSE_ASSERT(at < notes->get_size()); SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(notes->get_header()); ROSE_ASSERT(fhdr!=NULL); /* Length of note entry name, including NUL termination */ uint32_t u32; notes->read_content_local(at, &u32, 4); size_t name_size = disk_to_host(fhdr->get_sex(), u32); at += 4; /* Length of note entry description (i.e., the payload) */ notes->read_content_local(at, &u32, 4); size_t payload_size = disk_to_host(fhdr->get_sex(), u32); at += 4; /* Type of note */ notes->read_content_local(at, &u32, 4); unsigned type = disk_to_host(fhdr->get_sex(), u32); at += 4; /* NUL-terminated name */ std::string note_name = notes->read_content_local_str(at); ROSE_ASSERT(note_name.size()+1 == name_size); at += name_size; at = (at+3) & ~0x3; /* payload is aligned on a four-byte offset */ /* Set properties */ get_name()->set_string(note_name); set_type(type); p_payload = notes->read_content_local_ucl(at, payload_size); return at + payload_size; }
/** Initialize symbol by parsing a symbol table entry. An ELF String Section must be supplied in order to get the symbol name. */ void SgAsmElfSymbol::parse(ByteOrder sex, const Elf64SymbolEntry_disk *disk) { p_st_info = disk_to_host(sex, disk->st_info); p_st_res1 = disk_to_host(sex, disk->st_res1); p_st_shndx = disk_to_host(sex, disk->st_shndx); p_st_size = disk_to_host(sex, disk->st_size); p_value = disk_to_host(sex, disk->st_value); p_size = p_st_size; rose_addr_t name_offset = disk_to_host(sex, disk->st_name); get_name()->set_string(name_offset); parse_common(); }
/** Initialize by parsing a file. */ SgAsmElfEHFrameSection * SgAsmElfEHFrameSection::parse() { SgAsmElfSection::parse(); SgAsmElfFileHeader *fhdr = get_elf_header(); ROSE_ASSERT(fhdr!=NULL); rose_addr_t record_offset=0; std::map<rose_addr_t, SgAsmElfEHFrameEntryCI*> cies; while (record_offset<get_size()) { rose_addr_t at = record_offset; unsigned char u8_disk; uint32_t u32_disk; uint64_t u64_disk; /* Length or extended length */ rose_addr_t length_field_size = 4; /*number of bytes not counted in length*/ read_content_local(at, &u32_disk, 4); at += 4; rose_addr_t record_size = disk_to_host(fhdr->get_sex(), u32_disk); if (record_size==0xffffffff) { read_content_local(at, &u64_disk, 8); at += 8; record_size = disk_to_host(fhdr->get_sex(), u64_disk); length_field_size += 8; /*FIXME: it's not entirely clear whether ExtendedLength includes this field*/ } if (0==record_size) break; /* Backward offset to CIE record, or zero if this is a CIE record. */ read_content_local(at, &u32_disk, 4); at += 4; rose_addr_t cie_back_offset = disk_to_host(fhdr->get_sex(), u32_disk); if (0==cie_back_offset) { /* This is a CIE record */ SgAsmElfEHFrameEntryCI *cie = new SgAsmElfEHFrameEntryCI(this); cies[record_offset] = cie; /* Version */ uint8_t cie_version; read_content_local(at++, &cie_version, 1); cie->set_version(cie_version); /* Augmentation String */ std::string astr = read_content_local_str(at); at += astr.size() + 1; cie->set_augmentation_string(astr); /* Alignment factors */ cie->set_code_alignment_factor(read_content_local_uleb128(&at)); cie->set_data_alignment_factor(read_content_local_sleb128(&at)); /* Augmentation data length. This is apparently the length of the data described by the Augmentation String plus * the Initial Instructions plus any padding. [RPM 2009-01-15] */ cie->set_augmentation_data_length(read_content_local_uleb128(&at)); /* Augmentation data. The format of the augmentation data in the CIE record is determined by reading the * characters of the augmentation string. */ if (!astr.empty() && astr[0]=='z') { for (size_t i=1; i<astr.size(); i++) { if ('L'==astr[i]) { read_content_local(at++, &u8_disk, 1); cie->set_lsda_encoding(u8_disk); } else if ('P'==astr[i]) { /* The first byte is an encoding method which describes the following bytes, which are the address of * a Personality Routine Handler. There appears to be very little documentation about these fields. */ read_content_local(at++, &u8_disk, 1); cie->set_prh_encoding(u8_disk); switch (cie->get_prh_encoding()) { case 0x05: /* See Ubuntu 32bit /usr/bin/aptitude */ case 0x06: /* See second CIE record for Gentoo-Amd64 /usr/bin/addftinfo */ case 0x07: /* See first CIE record for Gentoo-Amd64 /usr/bin/addftinfo */ read_content_local(at++, &u8_disk, 1); /* not sure what this is; arg for __gxx_personality_v0? */ cie->set_prh_arg(u8_disk); read_content_local(at, &u32_disk, 4); at+=4; /* address of <__gxx_personality_v0@plt> */ cie->set_prh_addr(ByteOrder::le_to_host(u32_disk)); break; case 0x09: /* *.o file generated by gcc-4.0.x */ /* FIXME: Cannot find any info about this entry. Fix SgAsmElfEHFrameSection::parse() if we * ever figure this out. [RPM 2009-09-29] */ /*fallthrough*/ default: { if (++nwarnings<=WARNING_LIMIT) { fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64" has unknown PRH encoding 0x%02x\n", __FILE__, __LINE__, get_offset()+record_offset, cie->get_prh_encoding()); if (WARNING_LIMIT==nwarnings) fprintf(stderr, " (additional frame warnings will be suppressed)\n"); } break; } } } else if ('R'==astr[i]) { read_content_local(at++, &u8_disk, 1); cie->set_addr_encoding(u8_disk); } else if ('S'==astr[i]) { /* See http://lkml.indiana.edu/hypermail/linux/kernel/0602.3/1144.html and GCC PR #26208*/ cie->set_sig_frame(true); } else { /* Some stuff we don't handle yet. Warn about it and don't read anything. */ if (++nwarnings<=WARNING_LIMIT) { fprintf(stderr, "%s:%u: warning: ELF CIE 0x%08"PRIx64" has invalid augmentation string \"%s\"\n", __FILE__, __LINE__, get_offset()+record_offset, escapeString(astr).c_str()); if (WARNING_LIMIT==nwarnings) fprintf(stderr, " (additional frame warnings will be suppressed)\n"); } } } } /* Initial instructions. These are apparently included in the augmentation_data_length. The final instructions can * be zero padding (no-op instructions) to bring the record up to a multiple of the word size. */ rose_addr_t init_insn_size = (length_field_size + record_size) - (at - record_offset); cie->get_instructions() = read_content_local_ucl(at, init_insn_size); ROSE_ASSERT(cie->get_instructions().size()==init_insn_size); } else { /* This is a FDE record */ rose_addr_t cie_offset = record_offset + length_field_size - cie_back_offset; assert(cies.find(cie_offset)!=cies.end()); SgAsmElfEHFrameEntryCI *cie = cies[cie_offset]; SgAsmElfEHFrameEntryFD *fde = new SgAsmElfEHFrameEntryFD(cie); /* PC Begin (begin_rva) and size */ switch (cie->get_addr_encoding()) { case -1: /* No address encoding specified */ case 0x01: case 0x03: case 0x1b: /* Address doesn't look valid (e.g., 0xfffd74e8) but still four bytes [RPM 2008-01-16]*/ { read_content_local(at, &u32_disk, 4); at+=4; fde->set_begin_rva(ByteOrder::le_to_host(u32_disk)); read_content_local(at, &u32_disk, 4); at+=4; fde->set_size(ByteOrder::le_to_host(u32_disk)); break; } default: fprintf(stderr, "%s:%u: ELF CIE 0x%08"PRIx64", FDE 0x%08"PRIx64": unknown address encoding: 0x%02x\n", __FILE__, __LINE__, get_offset()+cie_offset, get_offset()+record_offset, cie->get_addr_encoding()); abort(); } /* Augmentation Data */ std::string astring = cie->get_augmentation_string(); if (astring.size()>0 && astring[0]=='z') { rose_addr_t aug_length = read_content_local_uleb128(&at); fde->get_augmentation_data() = read_content_local_ucl(at, aug_length); at += aug_length; ROSE_ASSERT(fde->get_augmentation_data().size()==aug_length); } /* Call frame instructions */ rose_addr_t cf_insn_size = (length_field_size + record_size) - (at - record_offset); fde->get_instructions() = read_content_local_ucl(at, cf_insn_size); ROSE_ASSERT(fde->get_instructions().size()==cf_insn_size); } record_offset += length_field_size + record_size; } return this; }