xref: /openbmc/qemu/include/hw/elf_ops.h.inc (revision 159fb790)
1*159fb790SPhilippe Mathieu-Daudéstatic void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
2*159fb790SPhilippe Mathieu-Daudé{
3*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_type);      /* Object file type */
4*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_machine);   /* Architecture */
5*159fb790SPhilippe Mathieu-Daudé    bswap32s(&ehdr->e_version);   /* Object file version */
6*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&ehdr->e_entry);     /* Entry point virtual address */
7*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&ehdr->e_phoff);     /* Program header table file offset */
8*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&ehdr->e_shoff);     /* Section header table file offset */
9*159fb790SPhilippe Mathieu-Daudé    bswap32s(&ehdr->e_flags);     /* Processor-specific flags */
10*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_ehsize);    /* ELF header size in bytes */
11*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
12*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_phnum);     /* Program header table entry count */
13*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
14*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_shnum);     /* Section header table entry count */
15*159fb790SPhilippe Mathieu-Daudé    bswap16s(&ehdr->e_shstrndx);  /* Section header string table index */
16*159fb790SPhilippe Mathieu-Daudé}
17*159fb790SPhilippe Mathieu-Daudé
18*159fb790SPhilippe Mathieu-Daudéstatic void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
19*159fb790SPhilippe Mathieu-Daudé{
20*159fb790SPhilippe Mathieu-Daudé    bswap32s(&phdr->p_type);   /* Segment type */
21*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&phdr->p_offset); /* Segment file offset */
22*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&phdr->p_vaddr);  /* Segment virtual address */
23*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&phdr->p_paddr);  /* Segment physical address */
24*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&phdr->p_filesz); /* Segment size in file */
25*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&phdr->p_memsz);  /* Segment size in memory */
26*159fb790SPhilippe Mathieu-Daudé    bswap32s(&phdr->p_flags);  /* Segment flags */
27*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&phdr->p_align);  /* Segment alignment */
28*159fb790SPhilippe Mathieu-Daudé}
29*159fb790SPhilippe Mathieu-Daudé
30*159fb790SPhilippe Mathieu-Daudéstatic void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
31*159fb790SPhilippe Mathieu-Daudé{
32*159fb790SPhilippe Mathieu-Daudé    bswap32s(&shdr->sh_name);
33*159fb790SPhilippe Mathieu-Daudé    bswap32s(&shdr->sh_type);
34*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&shdr->sh_flags);
35*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&shdr->sh_addr);
36*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&shdr->sh_offset);
37*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&shdr->sh_size);
38*159fb790SPhilippe Mathieu-Daudé    bswap32s(&shdr->sh_link);
39*159fb790SPhilippe Mathieu-Daudé    bswap32s(&shdr->sh_info);
40*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&shdr->sh_addralign);
41*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&shdr->sh_entsize);
42*159fb790SPhilippe Mathieu-Daudé}
43*159fb790SPhilippe Mathieu-Daudé
44*159fb790SPhilippe Mathieu-Daudéstatic void glue(bswap_sym, SZ)(struct elf_sym *sym)
45*159fb790SPhilippe Mathieu-Daudé{
46*159fb790SPhilippe Mathieu-Daudé    bswap32s(&sym->st_name);
47*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&sym->st_value);
48*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&sym->st_size);
49*159fb790SPhilippe Mathieu-Daudé    bswap16s(&sym->st_shndx);
50*159fb790SPhilippe Mathieu-Daudé}
51*159fb790SPhilippe Mathieu-Daudé
52*159fb790SPhilippe Mathieu-Daudéstatic void glue(bswap_rela, SZ)(struct elf_rela *rela)
53*159fb790SPhilippe Mathieu-Daudé{
54*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&rela->r_offset);
55*159fb790SPhilippe Mathieu-Daudé    bswapSZs(&rela->r_info);
56*159fb790SPhilippe Mathieu-Daudé    bswapSZs((elf_word *)&rela->r_addend);
57*159fb790SPhilippe Mathieu-Daudé}
58*159fb790SPhilippe Mathieu-Daudé
59*159fb790SPhilippe Mathieu-Daudéstatic struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
60*159fb790SPhilippe Mathieu-Daudé                                               int n, int type)
61*159fb790SPhilippe Mathieu-Daudé{
62*159fb790SPhilippe Mathieu-Daudé    int i;
63*159fb790SPhilippe Mathieu-Daudé    for(i=0;i<n;i++) {
64*159fb790SPhilippe Mathieu-Daudé        if (shdr_table[i].sh_type == type)
65*159fb790SPhilippe Mathieu-Daudé            return shdr_table + i;
66*159fb790SPhilippe Mathieu-Daudé    }
67*159fb790SPhilippe Mathieu-Daudé    return NULL;
68*159fb790SPhilippe Mathieu-Daudé}
69*159fb790SPhilippe Mathieu-Daudé
70*159fb790SPhilippe Mathieu-Daudéstatic int glue(symfind, SZ)(const void *s0, const void *s1)
71*159fb790SPhilippe Mathieu-Daudé{
72*159fb790SPhilippe Mathieu-Daudé    hwaddr addr = *(hwaddr *)s0;
73*159fb790SPhilippe Mathieu-Daudé    struct elf_sym *sym = (struct elf_sym *)s1;
74*159fb790SPhilippe Mathieu-Daudé    int result = 0;
75*159fb790SPhilippe Mathieu-Daudé    if (addr < sym->st_value) {
76*159fb790SPhilippe Mathieu-Daudé        result = -1;
77*159fb790SPhilippe Mathieu-Daudé    } else if (addr >= sym->st_value + sym->st_size) {
78*159fb790SPhilippe Mathieu-Daudé        result = 1;
79*159fb790SPhilippe Mathieu-Daudé    }
80*159fb790SPhilippe Mathieu-Daudé    return result;
81*159fb790SPhilippe Mathieu-Daudé}
82*159fb790SPhilippe Mathieu-Daudé
83*159fb790SPhilippe Mathieu-Daudéstatic const char *glue(lookup_symbol, SZ)(struct syminfo *s,
84*159fb790SPhilippe Mathieu-Daudé                                           hwaddr orig_addr)
85*159fb790SPhilippe Mathieu-Daudé{
86*159fb790SPhilippe Mathieu-Daudé    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
87*159fb790SPhilippe Mathieu-Daudé    struct elf_sym *sym;
88*159fb790SPhilippe Mathieu-Daudé
89*159fb790SPhilippe Mathieu-Daudé    sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
90*159fb790SPhilippe Mathieu-Daudé                  glue(symfind, SZ));
91*159fb790SPhilippe Mathieu-Daudé    if (sym != NULL) {
92*159fb790SPhilippe Mathieu-Daudé        return s->disas_strtab + sym->st_name;
93*159fb790SPhilippe Mathieu-Daudé    }
94*159fb790SPhilippe Mathieu-Daudé
95*159fb790SPhilippe Mathieu-Daudé    return "";
96*159fb790SPhilippe Mathieu-Daudé}
97*159fb790SPhilippe Mathieu-Daudé
98*159fb790SPhilippe Mathieu-Daudéstatic int glue(symcmp, SZ)(const void *s0, const void *s1)
99*159fb790SPhilippe Mathieu-Daudé{
100*159fb790SPhilippe Mathieu-Daudé    struct elf_sym *sym0 = (struct elf_sym *)s0;
101*159fb790SPhilippe Mathieu-Daudé    struct elf_sym *sym1 = (struct elf_sym *)s1;
102*159fb790SPhilippe Mathieu-Daudé    return (sym0->st_value < sym1->st_value)
103*159fb790SPhilippe Mathieu-Daudé        ? -1
104*159fb790SPhilippe Mathieu-Daudé        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
105*159fb790SPhilippe Mathieu-Daudé}
106*159fb790SPhilippe Mathieu-Daudé
107*159fb790SPhilippe Mathieu-Daudéstatic void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
108*159fb790SPhilippe Mathieu-Daudé                                   int clear_lsb, symbol_fn_t sym_cb)
109*159fb790SPhilippe Mathieu-Daudé{
110*159fb790SPhilippe Mathieu-Daudé    struct elf_shdr *symtab, *strtab;
111*159fb790SPhilippe Mathieu-Daudé    g_autofree struct elf_shdr *shdr_table = NULL;
112*159fb790SPhilippe Mathieu-Daudé    g_autofree struct elf_sym *syms = NULL;
113*159fb790SPhilippe Mathieu-Daudé    g_autofree char *str = NULL;
114*159fb790SPhilippe Mathieu-Daudé    struct syminfo *s;
115*159fb790SPhilippe Mathieu-Daudé    int nsyms, i;
116*159fb790SPhilippe Mathieu-Daudé
117*159fb790SPhilippe Mathieu-Daudé    shdr_table = load_at(fd, ehdr->e_shoff,
118*159fb790SPhilippe Mathieu-Daudé                         sizeof(struct elf_shdr) * ehdr->e_shnum);
119*159fb790SPhilippe Mathieu-Daudé    if (!shdr_table) {
120*159fb790SPhilippe Mathieu-Daudé        return;
121*159fb790SPhilippe Mathieu-Daudé    }
122*159fb790SPhilippe Mathieu-Daudé
123*159fb790SPhilippe Mathieu-Daudé    if (must_swab) {
124*159fb790SPhilippe Mathieu-Daudé        for (i = 0; i < ehdr->e_shnum; i++) {
125*159fb790SPhilippe Mathieu-Daudé            glue(bswap_shdr, SZ)(shdr_table + i);
126*159fb790SPhilippe Mathieu-Daudé        }
127*159fb790SPhilippe Mathieu-Daudé    }
128*159fb790SPhilippe Mathieu-Daudé
129*159fb790SPhilippe Mathieu-Daudé    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
130*159fb790SPhilippe Mathieu-Daudé    if (!symtab) {
131*159fb790SPhilippe Mathieu-Daudé        return;
132*159fb790SPhilippe Mathieu-Daudé    }
133*159fb790SPhilippe Mathieu-Daudé    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
134*159fb790SPhilippe Mathieu-Daudé    if (!syms) {
135*159fb790SPhilippe Mathieu-Daudé        return;
136*159fb790SPhilippe Mathieu-Daudé    }
137*159fb790SPhilippe Mathieu-Daudé
138*159fb790SPhilippe Mathieu-Daudé    nsyms = symtab->sh_size / sizeof(struct elf_sym);
139*159fb790SPhilippe Mathieu-Daudé
140*159fb790SPhilippe Mathieu-Daudé    /* String table */
141*159fb790SPhilippe Mathieu-Daudé    if (symtab->sh_link >= ehdr->e_shnum) {
142*159fb790SPhilippe Mathieu-Daudé        return;
143*159fb790SPhilippe Mathieu-Daudé    }
144*159fb790SPhilippe Mathieu-Daudé    strtab = &shdr_table[symtab->sh_link];
145*159fb790SPhilippe Mathieu-Daudé
146*159fb790SPhilippe Mathieu-Daudé    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
147*159fb790SPhilippe Mathieu-Daudé    if (!str) {
148*159fb790SPhilippe Mathieu-Daudé        return;
149*159fb790SPhilippe Mathieu-Daudé    }
150*159fb790SPhilippe Mathieu-Daudé
151*159fb790SPhilippe Mathieu-Daudé    i = 0;
152*159fb790SPhilippe Mathieu-Daudé    while (i < nsyms) {
153*159fb790SPhilippe Mathieu-Daudé        if (must_swab) {
154*159fb790SPhilippe Mathieu-Daudé            glue(bswap_sym, SZ)(&syms[i]);
155*159fb790SPhilippe Mathieu-Daudé        }
156*159fb790SPhilippe Mathieu-Daudé        if (sym_cb) {
157*159fb790SPhilippe Mathieu-Daudé            sym_cb(str + syms[i].st_name, syms[i].st_info,
158*159fb790SPhilippe Mathieu-Daudé                   syms[i].st_value, syms[i].st_size);
159*159fb790SPhilippe Mathieu-Daudé        }
160*159fb790SPhilippe Mathieu-Daudé        /* We are only interested in function symbols.
161*159fb790SPhilippe Mathieu-Daudé           Throw everything else away.  */
162*159fb790SPhilippe Mathieu-Daudé        if (syms[i].st_shndx == SHN_UNDEF ||
163*159fb790SPhilippe Mathieu-Daudé                syms[i].st_shndx >= SHN_LORESERVE ||
164*159fb790SPhilippe Mathieu-Daudé                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
165*159fb790SPhilippe Mathieu-Daudé            nsyms--;
166*159fb790SPhilippe Mathieu-Daudé            if (i < nsyms) {
167*159fb790SPhilippe Mathieu-Daudé                syms[i] = syms[nsyms];
168*159fb790SPhilippe Mathieu-Daudé            }
169*159fb790SPhilippe Mathieu-Daudé            continue;
170*159fb790SPhilippe Mathieu-Daudé        }
171*159fb790SPhilippe Mathieu-Daudé        if (clear_lsb) {
172*159fb790SPhilippe Mathieu-Daudé            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
173*159fb790SPhilippe Mathieu-Daudé            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
174*159fb790SPhilippe Mathieu-Daudé        }
175*159fb790SPhilippe Mathieu-Daudé        i++;
176*159fb790SPhilippe Mathieu-Daudé    }
177*159fb790SPhilippe Mathieu-Daudé
178*159fb790SPhilippe Mathieu-Daudé    /* check we have symbols left */
179*159fb790SPhilippe Mathieu-Daudé    if (nsyms == 0) {
180*159fb790SPhilippe Mathieu-Daudé        return;
181*159fb790SPhilippe Mathieu-Daudé    }
182*159fb790SPhilippe Mathieu-Daudé
183*159fb790SPhilippe Mathieu-Daudé    syms = g_realloc(syms, nsyms * sizeof(*syms));
184*159fb790SPhilippe Mathieu-Daudé    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
185*159fb790SPhilippe Mathieu-Daudé    for (i = 0; i < nsyms - 1; i++) {
186*159fb790SPhilippe Mathieu-Daudé        if (syms[i].st_size == 0) {
187*159fb790SPhilippe Mathieu-Daudé            syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
188*159fb790SPhilippe Mathieu-Daudé        }
189*159fb790SPhilippe Mathieu-Daudé    }
190*159fb790SPhilippe Mathieu-Daudé
191*159fb790SPhilippe Mathieu-Daudé    /* Commit */
192*159fb790SPhilippe Mathieu-Daudé    s = g_malloc0(sizeof(*s));
193*159fb790SPhilippe Mathieu-Daudé    s->lookup_symbol = glue(lookup_symbol, SZ);
194*159fb790SPhilippe Mathieu-Daudé    glue(s->disas_symtab.elf, SZ) = g_steal_pointer(&syms);
195*159fb790SPhilippe Mathieu-Daudé    s->disas_num_syms = nsyms;
196*159fb790SPhilippe Mathieu-Daudé    s->disas_strtab = g_steal_pointer(&str);
197*159fb790SPhilippe Mathieu-Daudé    s->next = syminfos;
198*159fb790SPhilippe Mathieu-Daudé    syminfos = s;
199*159fb790SPhilippe Mathieu-Daudé}
200*159fb790SPhilippe Mathieu-Daudé
201*159fb790SPhilippe Mathieu-Daudéstatic int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
202*159fb790SPhilippe Mathieu-Daudé                               uint64_t (*translate_fn)(void *, uint64_t),
203*159fb790SPhilippe Mathieu-Daudé                               void *translate_opaque, uint8_t *data,
204*159fb790SPhilippe Mathieu-Daudé                               struct elf_phdr *ph, int elf_machine)
205*159fb790SPhilippe Mathieu-Daudé{
206*159fb790SPhilippe Mathieu-Daudé    struct elf_shdr *reltab, *shdr_table = NULL;
207*159fb790SPhilippe Mathieu-Daudé    struct elf_rela *rels = NULL;
208*159fb790SPhilippe Mathieu-Daudé    int nrels, i, ret = -1;
209*159fb790SPhilippe Mathieu-Daudé    elf_word wordval;
210*159fb790SPhilippe Mathieu-Daudé    void *addr;
211*159fb790SPhilippe Mathieu-Daudé
212*159fb790SPhilippe Mathieu-Daudé    shdr_table = load_at(fd, ehdr->e_shoff,
213*159fb790SPhilippe Mathieu-Daudé                         sizeof(struct elf_shdr) * ehdr->e_shnum);
214*159fb790SPhilippe Mathieu-Daudé    if (!shdr_table) {
215*159fb790SPhilippe Mathieu-Daudé        return -1;
216*159fb790SPhilippe Mathieu-Daudé    }
217*159fb790SPhilippe Mathieu-Daudé    if (must_swab) {
218*159fb790SPhilippe Mathieu-Daudé        for (i = 0; i < ehdr->e_shnum; i++) {
219*159fb790SPhilippe Mathieu-Daudé            glue(bswap_shdr, SZ)(&shdr_table[i]);
220*159fb790SPhilippe Mathieu-Daudé        }
221*159fb790SPhilippe Mathieu-Daudé    }
222*159fb790SPhilippe Mathieu-Daudé
223*159fb790SPhilippe Mathieu-Daudé    reltab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_RELA);
224*159fb790SPhilippe Mathieu-Daudé    if (!reltab) {
225*159fb790SPhilippe Mathieu-Daudé        goto fail;
226*159fb790SPhilippe Mathieu-Daudé    }
227*159fb790SPhilippe Mathieu-Daudé    rels = load_at(fd, reltab->sh_offset, reltab->sh_size);
228*159fb790SPhilippe Mathieu-Daudé    if (!rels) {
229*159fb790SPhilippe Mathieu-Daudé        goto fail;
230*159fb790SPhilippe Mathieu-Daudé    }
231*159fb790SPhilippe Mathieu-Daudé    nrels = reltab->sh_size / sizeof(struct elf_rela);
232*159fb790SPhilippe Mathieu-Daudé
233*159fb790SPhilippe Mathieu-Daudé    for (i = 0; i < nrels; i++) {
234*159fb790SPhilippe Mathieu-Daudé        if (must_swab) {
235*159fb790SPhilippe Mathieu-Daudé            glue(bswap_rela, SZ)(&rels[i]);
236*159fb790SPhilippe Mathieu-Daudé        }
237*159fb790SPhilippe Mathieu-Daudé        if (rels[i].r_offset < ph->p_vaddr ||
238*159fb790SPhilippe Mathieu-Daudé            rels[i].r_offset >= ph->p_vaddr + ph->p_filesz) {
239*159fb790SPhilippe Mathieu-Daudé            continue;
240*159fb790SPhilippe Mathieu-Daudé        }
241*159fb790SPhilippe Mathieu-Daudé        addr = &data[rels[i].r_offset - ph->p_vaddr];
242*159fb790SPhilippe Mathieu-Daudé        switch (elf_machine) {
243*159fb790SPhilippe Mathieu-Daudé        case EM_S390:
244*159fb790SPhilippe Mathieu-Daudé            switch (rels[i].r_info) {
245*159fb790SPhilippe Mathieu-Daudé            case R_390_RELATIVE:
246*159fb790SPhilippe Mathieu-Daudé                wordval = *(elf_word *)addr;
247*159fb790SPhilippe Mathieu-Daudé                if (must_swab) {
248*159fb790SPhilippe Mathieu-Daudé                    bswapSZs(&wordval);
249*159fb790SPhilippe Mathieu-Daudé                }
250*159fb790SPhilippe Mathieu-Daudé                wordval = translate_fn(translate_opaque, wordval);
251*159fb790SPhilippe Mathieu-Daudé                if (must_swab) {
252*159fb790SPhilippe Mathieu-Daudé                    bswapSZs(&wordval);
253*159fb790SPhilippe Mathieu-Daudé                }
254*159fb790SPhilippe Mathieu-Daudé                *(elf_word *)addr = wordval;
255*159fb790SPhilippe Mathieu-Daudé                break;
256*159fb790SPhilippe Mathieu-Daudé            default:
257*159fb790SPhilippe Mathieu-Daudé                fprintf(stderr, "Unsupported relocation type %i!\n",
258*159fb790SPhilippe Mathieu-Daudé                        (int)rels[i].r_info);
259*159fb790SPhilippe Mathieu-Daudé            }
260*159fb790SPhilippe Mathieu-Daudé        }
261*159fb790SPhilippe Mathieu-Daudé    }
262*159fb790SPhilippe Mathieu-Daudé
263*159fb790SPhilippe Mathieu-Daudé    ret = 0;
264*159fb790SPhilippe Mathieu-Daudéfail:
265*159fb790SPhilippe Mathieu-Daudé    g_free(rels);
266*159fb790SPhilippe Mathieu-Daudé    g_free(shdr_table);
267*159fb790SPhilippe Mathieu-Daudé    return ret;
268*159fb790SPhilippe Mathieu-Daudé}
269*159fb790SPhilippe Mathieu-Daudé
270*159fb790SPhilippe Mathieu-Daudé/*
271*159fb790SPhilippe Mathieu-Daudé * Given 'nhdr', a pointer to a range of ELF Notes, search through them
272*159fb790SPhilippe Mathieu-Daudé * for a note matching type 'elf_note_type' and return a pointer to
273*159fb790SPhilippe Mathieu-Daudé * the matching ELF note.
274*159fb790SPhilippe Mathieu-Daudé */
275*159fb790SPhilippe Mathieu-Daudéstatic struct elf_note *glue(get_elf_note_type, SZ)(struct elf_note *nhdr,
276*159fb790SPhilippe Mathieu-Daudé                                                    elf_word note_size,
277*159fb790SPhilippe Mathieu-Daudé                                                    elf_word phdr_align,
278*159fb790SPhilippe Mathieu-Daudé                                                    elf_word elf_note_type)
279*159fb790SPhilippe Mathieu-Daudé{
280*159fb790SPhilippe Mathieu-Daudé    elf_word nhdr_size = sizeof(struct elf_note);
281*159fb790SPhilippe Mathieu-Daudé    elf_word elf_note_entry_offset = 0;
282*159fb790SPhilippe Mathieu-Daudé    elf_word note_type;
283*159fb790SPhilippe Mathieu-Daudé    elf_word nhdr_namesz;
284*159fb790SPhilippe Mathieu-Daudé    elf_word nhdr_descsz;
285*159fb790SPhilippe Mathieu-Daudé
286*159fb790SPhilippe Mathieu-Daudé    if (nhdr == NULL) {
287*159fb790SPhilippe Mathieu-Daudé        return NULL;
288*159fb790SPhilippe Mathieu-Daudé    }
289*159fb790SPhilippe Mathieu-Daudé
290*159fb790SPhilippe Mathieu-Daudé    note_type = nhdr->n_type;
291*159fb790SPhilippe Mathieu-Daudé    while (note_type != elf_note_type) {
292*159fb790SPhilippe Mathieu-Daudé        nhdr_namesz = nhdr->n_namesz;
293*159fb790SPhilippe Mathieu-Daudé        nhdr_descsz = nhdr->n_descsz;
294*159fb790SPhilippe Mathieu-Daudé
295*159fb790SPhilippe Mathieu-Daudé        elf_note_entry_offset = nhdr_size +
296*159fb790SPhilippe Mathieu-Daudé            QEMU_ALIGN_UP(nhdr_namesz, phdr_align) +
297*159fb790SPhilippe Mathieu-Daudé            QEMU_ALIGN_UP(nhdr_descsz, phdr_align);
298*159fb790SPhilippe Mathieu-Daudé
299*159fb790SPhilippe Mathieu-Daudé        /*
300*159fb790SPhilippe Mathieu-Daudé         * If the offset calculated in this iteration exceeds the
301*159fb790SPhilippe Mathieu-Daudé         * supplied size, we are done and no matching note was found.
302*159fb790SPhilippe Mathieu-Daudé         */
303*159fb790SPhilippe Mathieu-Daudé        if (elf_note_entry_offset > note_size) {
304*159fb790SPhilippe Mathieu-Daudé            return NULL;
305*159fb790SPhilippe Mathieu-Daudé        }
306*159fb790SPhilippe Mathieu-Daudé
307*159fb790SPhilippe Mathieu-Daudé        /* skip to the next ELF Note entry */
308*159fb790SPhilippe Mathieu-Daudé        nhdr = (void *)nhdr + elf_note_entry_offset;
309*159fb790SPhilippe Mathieu-Daudé        note_type = nhdr->n_type;
310*159fb790SPhilippe Mathieu-Daudé    }
311*159fb790SPhilippe Mathieu-Daudé
312*159fb790SPhilippe Mathieu-Daudé    return nhdr;
313*159fb790SPhilippe Mathieu-Daudé}
314*159fb790SPhilippe Mathieu-Daudé
315*159fb790SPhilippe Mathieu-Daudéstatic ssize_t glue(load_elf, SZ)(const char *name, int fd,
316*159fb790SPhilippe Mathieu-Daudé                                  uint64_t (*elf_note_fn)(void *, void *, bool),
317*159fb790SPhilippe Mathieu-Daudé                                  uint64_t (*translate_fn)(void *, uint64_t),
318*159fb790SPhilippe Mathieu-Daudé                                  void *translate_opaque,
319*159fb790SPhilippe Mathieu-Daudé                                  int must_swab, uint64_t *pentry,
320*159fb790SPhilippe Mathieu-Daudé                                  uint64_t *lowaddr, uint64_t *highaddr,
321*159fb790SPhilippe Mathieu-Daudé                                  uint32_t *pflags, int elf_machine,
322*159fb790SPhilippe Mathieu-Daudé                                  int clear_lsb, int data_swab,
323*159fb790SPhilippe Mathieu-Daudé                                  AddressSpace *as, bool load_rom,
324*159fb790SPhilippe Mathieu-Daudé                                  symbol_fn_t sym_cb)
325*159fb790SPhilippe Mathieu-Daudé{
326*159fb790SPhilippe Mathieu-Daudé    struct elfhdr ehdr;
327*159fb790SPhilippe Mathieu-Daudé    struct elf_phdr *phdr = NULL, *ph;
328*159fb790SPhilippe Mathieu-Daudé    int size, i;
329*159fb790SPhilippe Mathieu-Daudé    ssize_t total_size;
330*159fb790SPhilippe Mathieu-Daudé    elf_word mem_size, file_size, data_offset;
331*159fb790SPhilippe Mathieu-Daudé    uint64_t addr, low = (uint64_t)-1, high = 0;
332*159fb790SPhilippe Mathieu-Daudé    GMappedFile *mapped_file = NULL;
333*159fb790SPhilippe Mathieu-Daudé    uint8_t *data = NULL;
334*159fb790SPhilippe Mathieu-Daudé    ssize_t ret = ELF_LOAD_FAILED;
335*159fb790SPhilippe Mathieu-Daudé
336*159fb790SPhilippe Mathieu-Daudé    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
337*159fb790SPhilippe Mathieu-Daudé        goto fail;
338*159fb790SPhilippe Mathieu-Daudé    if (must_swab) {
339*159fb790SPhilippe Mathieu-Daudé        glue(bswap_ehdr, SZ)(&ehdr);
340*159fb790SPhilippe Mathieu-Daudé    }
341*159fb790SPhilippe Mathieu-Daudé
342*159fb790SPhilippe Mathieu-Daudé    if (elf_machine <= EM_NONE) {
343*159fb790SPhilippe Mathieu-Daudé        /* The caller didn't specify an ARCH, we can figure it out */
344*159fb790SPhilippe Mathieu-Daudé        elf_machine = ehdr.e_machine;
345*159fb790SPhilippe Mathieu-Daudé    }
346*159fb790SPhilippe Mathieu-Daudé
347*159fb790SPhilippe Mathieu-Daudé    switch (elf_machine) {
348*159fb790SPhilippe Mathieu-Daudé        case EM_PPC64:
349*159fb790SPhilippe Mathieu-Daudé            if (ehdr.e_machine != EM_PPC64) {
350*159fb790SPhilippe Mathieu-Daudé                if (ehdr.e_machine != EM_PPC) {
351*159fb790SPhilippe Mathieu-Daudé                    ret = ELF_LOAD_WRONG_ARCH;
352*159fb790SPhilippe Mathieu-Daudé                    goto fail;
353*159fb790SPhilippe Mathieu-Daudé                }
354*159fb790SPhilippe Mathieu-Daudé            }
355*159fb790SPhilippe Mathieu-Daudé            break;
356*159fb790SPhilippe Mathieu-Daudé        case EM_X86_64:
357*159fb790SPhilippe Mathieu-Daudé            if (ehdr.e_machine != EM_X86_64) {
358*159fb790SPhilippe Mathieu-Daudé                if (ehdr.e_machine != EM_386) {
359*159fb790SPhilippe Mathieu-Daudé                    ret = ELF_LOAD_WRONG_ARCH;
360*159fb790SPhilippe Mathieu-Daudé                    goto fail;
361*159fb790SPhilippe Mathieu-Daudé                }
362*159fb790SPhilippe Mathieu-Daudé            }
363*159fb790SPhilippe Mathieu-Daudé            break;
364*159fb790SPhilippe Mathieu-Daudé        case EM_MICROBLAZE:
365*159fb790SPhilippe Mathieu-Daudé            if (ehdr.e_machine != EM_MICROBLAZE) {
366*159fb790SPhilippe Mathieu-Daudé                if (ehdr.e_machine != EM_MICROBLAZE_OLD) {
367*159fb790SPhilippe Mathieu-Daudé                    ret = ELF_LOAD_WRONG_ARCH;
368*159fb790SPhilippe Mathieu-Daudé                    goto fail;
369*159fb790SPhilippe Mathieu-Daudé                }
370*159fb790SPhilippe Mathieu-Daudé            }
371*159fb790SPhilippe Mathieu-Daudé            break;
372*159fb790SPhilippe Mathieu-Daudé        case EM_MIPS:
373*159fb790SPhilippe Mathieu-Daudé        case EM_NANOMIPS:
374*159fb790SPhilippe Mathieu-Daudé            if ((ehdr.e_machine != EM_MIPS) &&
375*159fb790SPhilippe Mathieu-Daudé                (ehdr.e_machine != EM_NANOMIPS)) {
376*159fb790SPhilippe Mathieu-Daudé                ret = ELF_LOAD_WRONG_ARCH;
377*159fb790SPhilippe Mathieu-Daudé                goto fail;
378*159fb790SPhilippe Mathieu-Daudé            }
379*159fb790SPhilippe Mathieu-Daudé            break;
380*159fb790SPhilippe Mathieu-Daudé        default:
381*159fb790SPhilippe Mathieu-Daudé            if (elf_machine != ehdr.e_machine) {
382*159fb790SPhilippe Mathieu-Daudé                ret = ELF_LOAD_WRONG_ARCH;
383*159fb790SPhilippe Mathieu-Daudé                goto fail;
384*159fb790SPhilippe Mathieu-Daudé            }
385*159fb790SPhilippe Mathieu-Daudé    }
386*159fb790SPhilippe Mathieu-Daudé
387*159fb790SPhilippe Mathieu-Daudé    if (pflags) {
388*159fb790SPhilippe Mathieu-Daudé        *pflags = ehdr.e_flags;
389*159fb790SPhilippe Mathieu-Daudé    }
390*159fb790SPhilippe Mathieu-Daudé    if (pentry) {
391*159fb790SPhilippe Mathieu-Daudé        *pentry = ehdr.e_entry;
392*159fb790SPhilippe Mathieu-Daudé    }
393*159fb790SPhilippe Mathieu-Daudé
394*159fb790SPhilippe Mathieu-Daudé    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb);
395*159fb790SPhilippe Mathieu-Daudé
396*159fb790SPhilippe Mathieu-Daudé    size = ehdr.e_phnum * sizeof(phdr[0]);
397*159fb790SPhilippe Mathieu-Daudé    if (lseek(fd, ehdr.e_phoff, SEEK_SET) != ehdr.e_phoff) {
398*159fb790SPhilippe Mathieu-Daudé        goto fail;
399*159fb790SPhilippe Mathieu-Daudé    }
400*159fb790SPhilippe Mathieu-Daudé    phdr = g_malloc0(size);
401*159fb790SPhilippe Mathieu-Daudé    if (!phdr)
402*159fb790SPhilippe Mathieu-Daudé        goto fail;
403*159fb790SPhilippe Mathieu-Daudé    if (read(fd, phdr, size) != size)
404*159fb790SPhilippe Mathieu-Daudé        goto fail;
405*159fb790SPhilippe Mathieu-Daudé    if (must_swab) {
406*159fb790SPhilippe Mathieu-Daudé        for(i = 0; i < ehdr.e_phnum; i++) {
407*159fb790SPhilippe Mathieu-Daudé            ph = &phdr[i];
408*159fb790SPhilippe Mathieu-Daudé            glue(bswap_phdr, SZ)(ph);
409*159fb790SPhilippe Mathieu-Daudé        }
410*159fb790SPhilippe Mathieu-Daudé    }
411*159fb790SPhilippe Mathieu-Daudé
412*159fb790SPhilippe Mathieu-Daudé    /*
413*159fb790SPhilippe Mathieu-Daudé     * Since we want to be able to modify the mapped buffer, we set the
414*159fb790SPhilippe Mathieu-Daudé     * 'writable' parameter to 'true'. Modifications to the buffer are not
415*159fb790SPhilippe Mathieu-Daudé     * written back to the file.
416*159fb790SPhilippe Mathieu-Daudé     */
417*159fb790SPhilippe Mathieu-Daudé    mapped_file = g_mapped_file_new_from_fd(fd, true, NULL);
418*159fb790SPhilippe Mathieu-Daudé    if (!mapped_file) {
419*159fb790SPhilippe Mathieu-Daudé        goto fail;
420*159fb790SPhilippe Mathieu-Daudé    }
421*159fb790SPhilippe Mathieu-Daudé
422*159fb790SPhilippe Mathieu-Daudé    total_size = 0;
423*159fb790SPhilippe Mathieu-Daudé    for(i = 0; i < ehdr.e_phnum; i++) {
424*159fb790SPhilippe Mathieu-Daudé        ph = &phdr[i];
425*159fb790SPhilippe Mathieu-Daudé        if (ph->p_type == PT_LOAD) {
426*159fb790SPhilippe Mathieu-Daudé            mem_size = ph->p_memsz; /* Size of the ROM */
427*159fb790SPhilippe Mathieu-Daudé            file_size = ph->p_filesz; /* Size of the allocated data */
428*159fb790SPhilippe Mathieu-Daudé            data_offset = ph->p_offset; /* Offset where the data is located */
429*159fb790SPhilippe Mathieu-Daudé
430*159fb790SPhilippe Mathieu-Daudé            if (file_size > 0) {
431*159fb790SPhilippe Mathieu-Daudé                if (g_mapped_file_get_length(mapped_file) <
432*159fb790SPhilippe Mathieu-Daudé                    file_size + data_offset) {
433*159fb790SPhilippe Mathieu-Daudé                    goto fail;
434*159fb790SPhilippe Mathieu-Daudé                }
435*159fb790SPhilippe Mathieu-Daudé
436*159fb790SPhilippe Mathieu-Daudé                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
437*159fb790SPhilippe Mathieu-Daudé                data += data_offset;
438*159fb790SPhilippe Mathieu-Daudé            }
439*159fb790SPhilippe Mathieu-Daudé
440*159fb790SPhilippe Mathieu-Daudé            /* The ELF spec is somewhat vague about the purpose of the
441*159fb790SPhilippe Mathieu-Daudé             * physical address field. One common use in the embedded world
442*159fb790SPhilippe Mathieu-Daudé             * is that physical address field specifies the load address
443*159fb790SPhilippe Mathieu-Daudé             * and the virtual address field specifies the execution address.
444*159fb790SPhilippe Mathieu-Daudé             * Segments are packed into ROM or flash, and the relocation
445*159fb790SPhilippe Mathieu-Daudé             * and zero-initialization of data is done at runtime. This
446*159fb790SPhilippe Mathieu-Daudé             * means that the memsz header represents the runtime size of the
447*159fb790SPhilippe Mathieu-Daudé             * segment, but the filesz represents the loadtime size. If
448*159fb790SPhilippe Mathieu-Daudé             * we try to honour the memsz value for an ELF file like this
449*159fb790SPhilippe Mathieu-Daudé             * we will end up with overlapping segments (which the
450*159fb790SPhilippe Mathieu-Daudé             * loader.c code will later reject).
451*159fb790SPhilippe Mathieu-Daudé             * We support ELF files using this scheme by by checking whether
452*159fb790SPhilippe Mathieu-Daudé             * paddr + memsz for this segment would overlap with any other
453*159fb790SPhilippe Mathieu-Daudé             * segment. If so, then we assume it's using this scheme and
454*159fb790SPhilippe Mathieu-Daudé             * truncate the loaded segment to the filesz size.
455*159fb790SPhilippe Mathieu-Daudé             * If the segment considered as being memsz size doesn't overlap
456*159fb790SPhilippe Mathieu-Daudé             * then we use memsz for the segment length, to handle ELF files
457*159fb790SPhilippe Mathieu-Daudé             * which assume that the loader will do the zero-initialization.
458*159fb790SPhilippe Mathieu-Daudé             */
459*159fb790SPhilippe Mathieu-Daudé            if (mem_size > file_size) {
460*159fb790SPhilippe Mathieu-Daudé                /* If this segment's zero-init portion overlaps another
461*159fb790SPhilippe Mathieu-Daudé                 * segment's data or zero-init portion, then truncate this one.
462*159fb790SPhilippe Mathieu-Daudé                 * Invalid ELF files where the segments overlap even when
463*159fb790SPhilippe Mathieu-Daudé                 * only file_size bytes are loaded will be rejected by
464*159fb790SPhilippe Mathieu-Daudé                 * the ROM overlap check in loader.c, so we don't try to
465*159fb790SPhilippe Mathieu-Daudé                 * explicitly detect those here.
466*159fb790SPhilippe Mathieu-Daudé                 */
467*159fb790SPhilippe Mathieu-Daudé                int j;
468*159fb790SPhilippe Mathieu-Daudé                elf_word zero_start = ph->p_paddr + file_size;
469*159fb790SPhilippe Mathieu-Daudé                elf_word zero_end = ph->p_paddr + mem_size;
470*159fb790SPhilippe Mathieu-Daudé
471*159fb790SPhilippe Mathieu-Daudé                for (j = 0; j < ehdr.e_phnum; j++) {
472*159fb790SPhilippe Mathieu-Daudé                    struct elf_phdr *jph = &phdr[j];
473*159fb790SPhilippe Mathieu-Daudé
474*159fb790SPhilippe Mathieu-Daudé                    if (i != j && jph->p_type == PT_LOAD) {
475*159fb790SPhilippe Mathieu-Daudé                        elf_word other_start = jph->p_paddr;
476*159fb790SPhilippe Mathieu-Daudé                        elf_word other_end = jph->p_paddr + jph->p_memsz;
477*159fb790SPhilippe Mathieu-Daudé
478*159fb790SPhilippe Mathieu-Daudé                        if (!(other_start >= zero_end ||
479*159fb790SPhilippe Mathieu-Daudé                              zero_start >= other_end)) {
480*159fb790SPhilippe Mathieu-Daudé                            mem_size = file_size;
481*159fb790SPhilippe Mathieu-Daudé                            break;
482*159fb790SPhilippe Mathieu-Daudé                        }
483*159fb790SPhilippe Mathieu-Daudé                    }
484*159fb790SPhilippe Mathieu-Daudé                }
485*159fb790SPhilippe Mathieu-Daudé            }
486*159fb790SPhilippe Mathieu-Daudé
487*159fb790SPhilippe Mathieu-Daudé            if (mem_size > SSIZE_MAX - total_size) {
488*159fb790SPhilippe Mathieu-Daudé                ret = ELF_LOAD_TOO_BIG;
489*159fb790SPhilippe Mathieu-Daudé                goto fail;
490*159fb790SPhilippe Mathieu-Daudé            }
491*159fb790SPhilippe Mathieu-Daudé
492*159fb790SPhilippe Mathieu-Daudé            /* address_offset is hack for kernel images that are
493*159fb790SPhilippe Mathieu-Daudé               linked at the wrong physical address.  */
494*159fb790SPhilippe Mathieu-Daudé            if (translate_fn) {
495*159fb790SPhilippe Mathieu-Daudé                addr = translate_fn(translate_opaque, ph->p_paddr);
496*159fb790SPhilippe Mathieu-Daudé                glue(elf_reloc, SZ)(&ehdr, fd, must_swab,  translate_fn,
497*159fb790SPhilippe Mathieu-Daudé                                    translate_opaque, data, ph, elf_machine);
498*159fb790SPhilippe Mathieu-Daudé            } else {
499*159fb790SPhilippe Mathieu-Daudé                addr = ph->p_paddr;
500*159fb790SPhilippe Mathieu-Daudé            }
501*159fb790SPhilippe Mathieu-Daudé
502*159fb790SPhilippe Mathieu-Daudé            if (data_swab) {
503*159fb790SPhilippe Mathieu-Daudé                elf_word j;
504*159fb790SPhilippe Mathieu-Daudé                for (j = 0; j < file_size; j += (1 << data_swab)) {
505*159fb790SPhilippe Mathieu-Daudé                    uint8_t *dp = data + j;
506*159fb790SPhilippe Mathieu-Daudé                    switch (data_swab) {
507*159fb790SPhilippe Mathieu-Daudé                    case (1):
508*159fb790SPhilippe Mathieu-Daudé                        *(uint16_t *)dp = bswap16(*(uint16_t *)dp);
509*159fb790SPhilippe Mathieu-Daudé                        break;
510*159fb790SPhilippe Mathieu-Daudé                    case (2):
511*159fb790SPhilippe Mathieu-Daudé                        *(uint32_t *)dp = bswap32(*(uint32_t *)dp);
512*159fb790SPhilippe Mathieu-Daudé                        break;
513*159fb790SPhilippe Mathieu-Daudé                    case (3):
514*159fb790SPhilippe Mathieu-Daudé                        *(uint64_t *)dp = bswap64(*(uint64_t *)dp);
515*159fb790SPhilippe Mathieu-Daudé                        break;
516*159fb790SPhilippe Mathieu-Daudé                    default:
517*159fb790SPhilippe Mathieu-Daudé                        g_assert_not_reached();
518*159fb790SPhilippe Mathieu-Daudé                    }
519*159fb790SPhilippe Mathieu-Daudé                }
520*159fb790SPhilippe Mathieu-Daudé            }
521*159fb790SPhilippe Mathieu-Daudé
522*159fb790SPhilippe Mathieu-Daudé            /* the entry pointer in the ELF header is a virtual
523*159fb790SPhilippe Mathieu-Daudé             * address, if the text segments paddr and vaddr differ
524*159fb790SPhilippe Mathieu-Daudé             * we need to adjust the entry */
525*159fb790SPhilippe Mathieu-Daudé            if (pentry && !translate_fn &&
526*159fb790SPhilippe Mathieu-Daudé                    ph->p_vaddr != ph->p_paddr &&
527*159fb790SPhilippe Mathieu-Daudé                    ehdr.e_entry >= ph->p_vaddr &&
528*159fb790SPhilippe Mathieu-Daudé                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
529*159fb790SPhilippe Mathieu-Daudé                    ph->p_flags & PF_X) {
530*159fb790SPhilippe Mathieu-Daudé                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
531*159fb790SPhilippe Mathieu-Daudé            }
532*159fb790SPhilippe Mathieu-Daudé
533*159fb790SPhilippe Mathieu-Daudé            /* Some ELF files really do have segments of zero size;
534*159fb790SPhilippe Mathieu-Daudé             * just ignore them rather than trying to create empty
535*159fb790SPhilippe Mathieu-Daudé             * ROM blobs, because the zero-length blob can falsely
536*159fb790SPhilippe Mathieu-Daudé             * trigger the overlapping-ROM-blobs check.
537*159fb790SPhilippe Mathieu-Daudé             */
538*159fb790SPhilippe Mathieu-Daudé            if (mem_size != 0) {
539*159fb790SPhilippe Mathieu-Daudé                if (load_rom) {
540*159fb790SPhilippe Mathieu-Daudé                    g_autofree char *label =
541*159fb790SPhilippe Mathieu-Daudé                        g_strdup_printf("%s ELF program header segment %d",
542*159fb790SPhilippe Mathieu-Daudé                                        name, i);
543*159fb790SPhilippe Mathieu-Daudé
544*159fb790SPhilippe Mathieu-Daudé                    /*
545*159fb790SPhilippe Mathieu-Daudé                     * rom_add_elf_program() takes its own reference to
546*159fb790SPhilippe Mathieu-Daudé                     * 'mapped_file'.
547*159fb790SPhilippe Mathieu-Daudé                     */
548*159fb790SPhilippe Mathieu-Daudé                    rom_add_elf_program(label, mapped_file, data, file_size,
549*159fb790SPhilippe Mathieu-Daudé                                        mem_size, addr, as);
550*159fb790SPhilippe Mathieu-Daudé                } else {
551*159fb790SPhilippe Mathieu-Daudé                    MemTxResult res;
552*159fb790SPhilippe Mathieu-Daudé
553*159fb790SPhilippe Mathieu-Daudé                    res = address_space_write(as ? as : &address_space_memory,
554*159fb790SPhilippe Mathieu-Daudé                                              addr, MEMTXATTRS_UNSPECIFIED,
555*159fb790SPhilippe Mathieu-Daudé                                              data, file_size);
556*159fb790SPhilippe Mathieu-Daudé                    if (res != MEMTX_OK) {
557*159fb790SPhilippe Mathieu-Daudé                        goto fail;
558*159fb790SPhilippe Mathieu-Daudé                    }
559*159fb790SPhilippe Mathieu-Daudé                    /*
560*159fb790SPhilippe Mathieu-Daudé                     * We need to zero'ify the space that is not copied
561*159fb790SPhilippe Mathieu-Daudé                     * from file
562*159fb790SPhilippe Mathieu-Daudé                     */
563*159fb790SPhilippe Mathieu-Daudé                    if (file_size < mem_size) {
564*159fb790SPhilippe Mathieu-Daudé                        res = address_space_set(as ? as : &address_space_memory,
565*159fb790SPhilippe Mathieu-Daudé                                                addr + file_size, 0,
566*159fb790SPhilippe Mathieu-Daudé                                                mem_size - file_size,
567*159fb790SPhilippe Mathieu-Daudé                                                MEMTXATTRS_UNSPECIFIED);
568*159fb790SPhilippe Mathieu-Daudé                        if (res != MEMTX_OK) {
569*159fb790SPhilippe Mathieu-Daudé                            goto fail;
570*159fb790SPhilippe Mathieu-Daudé                        }
571*159fb790SPhilippe Mathieu-Daudé                    }
572*159fb790SPhilippe Mathieu-Daudé                }
573*159fb790SPhilippe Mathieu-Daudé            }
574*159fb790SPhilippe Mathieu-Daudé
575*159fb790SPhilippe Mathieu-Daudé            total_size += mem_size;
576*159fb790SPhilippe Mathieu-Daudé            if (addr < low)
577*159fb790SPhilippe Mathieu-Daudé                low = addr;
578*159fb790SPhilippe Mathieu-Daudé            if ((addr + mem_size) > high)
579*159fb790SPhilippe Mathieu-Daudé                high = addr + mem_size;
580*159fb790SPhilippe Mathieu-Daudé
581*159fb790SPhilippe Mathieu-Daudé            data = NULL;
582*159fb790SPhilippe Mathieu-Daudé
583*159fb790SPhilippe Mathieu-Daudé        } else if (ph->p_type == PT_NOTE && elf_note_fn) {
584*159fb790SPhilippe Mathieu-Daudé            struct elf_note *nhdr = NULL;
585*159fb790SPhilippe Mathieu-Daudé
586*159fb790SPhilippe Mathieu-Daudé            file_size = ph->p_filesz; /* Size of the range of ELF notes */
587*159fb790SPhilippe Mathieu-Daudé            data_offset = ph->p_offset; /* Offset where the notes are located */
588*159fb790SPhilippe Mathieu-Daudé
589*159fb790SPhilippe Mathieu-Daudé            if (file_size > 0) {
590*159fb790SPhilippe Mathieu-Daudé                if (g_mapped_file_get_length(mapped_file) <
591*159fb790SPhilippe Mathieu-Daudé                    file_size + data_offset) {
592*159fb790SPhilippe Mathieu-Daudé                    goto fail;
593*159fb790SPhilippe Mathieu-Daudé                }
594*159fb790SPhilippe Mathieu-Daudé
595*159fb790SPhilippe Mathieu-Daudé                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
596*159fb790SPhilippe Mathieu-Daudé                data += data_offset;
597*159fb790SPhilippe Mathieu-Daudé            }
598*159fb790SPhilippe Mathieu-Daudé
599*159fb790SPhilippe Mathieu-Daudé            /*
600*159fb790SPhilippe Mathieu-Daudé             * Search the ELF notes to find one with a type matching the
601*159fb790SPhilippe Mathieu-Daudé             * value passed in via 'translate_opaque'
602*159fb790SPhilippe Mathieu-Daudé             */
603*159fb790SPhilippe Mathieu-Daudé            nhdr = (struct elf_note *)data;
604*159fb790SPhilippe Mathieu-Daudé            assert(translate_opaque != NULL);
605*159fb790SPhilippe Mathieu-Daudé            nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
606*159fb790SPhilippe Mathieu-Daudé                                               *(uint64_t *)translate_opaque);
607*159fb790SPhilippe Mathieu-Daudé            if (nhdr != NULL) {
608*159fb790SPhilippe Mathieu-Daudé                elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
609*159fb790SPhilippe Mathieu-Daudé            }
610*159fb790SPhilippe Mathieu-Daudé            data = NULL;
611*159fb790SPhilippe Mathieu-Daudé        }
612*159fb790SPhilippe Mathieu-Daudé    }
613*159fb790SPhilippe Mathieu-Daudé
614*159fb790SPhilippe Mathieu-Daudé    if (lowaddr) {
615*159fb790SPhilippe Mathieu-Daudé        *lowaddr = low;
616*159fb790SPhilippe Mathieu-Daudé    }
617*159fb790SPhilippe Mathieu-Daudé    if (highaddr) {
618*159fb790SPhilippe Mathieu-Daudé        *highaddr = high;
619*159fb790SPhilippe Mathieu-Daudé    }
620*159fb790SPhilippe Mathieu-Daudé    ret = total_size;
621*159fb790SPhilippe Mathieu-Daudé fail:
622*159fb790SPhilippe Mathieu-Daudé    if (mapped_file) {
623*159fb790SPhilippe Mathieu-Daudé        g_mapped_file_unref(mapped_file);
624*159fb790SPhilippe Mathieu-Daudé    }
625*159fb790SPhilippe Mathieu-Daudé    g_free(phdr);
626*159fb790SPhilippe Mathieu-Daudé    return ret;
627*159fb790SPhilippe Mathieu-Daudé}
628