Coverage Report

Created: 2025-11-11 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/upx/src/p_vmlinx.cpp
Line
Count
Source
1
/* p_vmlinx.cpp -- pack vmlinux ET_EXEC file (before bootsect or setup)
2
3
   This file is part of the UPX executable compressor.
4
5
   Copyright (C) 2004-2025 John Reiser
6
   Copyright (C) 1996-2025 Markus Franz Xaver Johannes Oberhumer
7
   Copyright (C) 1996-2025 Laszlo Molnar
8
   All Rights Reserved.
9
10
   UPX and the UCL library are free software; you can redistribute them
11
   and/or modify them under the terms of the GNU General Public License as
12
   published by the Free Software Foundation; either version 2 of
13
   the License, or (at your option) any later version.
14
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
20
   You should have received a copy of the GNU General Public License
21
   along with this program; see the file COPYING.
22
   If not, write to the Free Software Foundation, Inc.,
23
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25
   Markus F.X.J. Oberhumer              Laszlo Molnar
26
   <markus@oberhumer.com>               <ezerotven+github@gmail.com>
27
28
   John Reiser
29
   <jreiser@users.sourceforge.net>
30
 */
31
32
33
#define ALLOW_INT_PLUS_MEMBUFFER 1
34
#include "conf.h"
35
36
#include "file.h"
37
#include "filter.h"
38
#include "packer.h"
39
#include "p_vmlinx.h"
40
#include "linker.h"
41
42
static const CLANG_FORMAT_DUMMY_STATEMENT
43
#include "stub/i386-linux.kernel.vmlinux.h"
44
static const CLANG_FORMAT_DUMMY_STATEMENT
45
#include "stub/amd64-linux.kernel.vmlinux.h"
46
static const CLANG_FORMAT_DUMMY_STATEMENT
47
#include "stub/arm.v5a-linux.kernel.vmlinux.h"
48
static const CLANG_FORMAT_DUMMY_STATEMENT
49
#include "stub/armeb.v5a-linux.kernel.vmlinux.h"
50
static const CLANG_FORMAT_DUMMY_STATEMENT
51
#include "stub/powerpc-linux.kernel.vmlinux.h"
52
53
54
/*************************************************************************
55
//
56
**************************************************************************/
57
58
template <class T>
59
PackVmlinuxBase<T>::PackVmlinuxBase(InputFile *f,
60
                                    unsigned e_machine, unsigned elfclass, unsigned elfdata,
61
                                    char const *const boot_label) :
62
137k
    super(f),
63
137k
    my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata),
64
137k
    my_boot_label(boot_label),
65
137k
    n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr)
66
137k
{
67
137k
    ElfClass::compileTimeAssertions();
68
137k
    bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr);
69
137k
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::PackVmlinuxBase(InputFile*, unsigned int, unsigned int, unsigned int, char const*)
Line
Count
Source
62
45.7k
    super(f),
63
45.7k
    my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata),
64
45.7k
    my_boot_label(boot_label),
65
45.7k
    n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr)
66
45.7k
{
67
45.7k
    ElfClass::compileTimeAssertions();
68
45.7k
    bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr);
69
45.7k
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::PackVmlinuxBase(InputFile*, unsigned int, unsigned int, unsigned int, char const*)
Line
Count
Source
62
45.7k
    super(f),
63
45.7k
    my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata),
64
45.7k
    my_boot_label(boot_label),
65
45.7k
    n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr)
66
45.7k
{
67
45.7k
    ElfClass::compileTimeAssertions();
68
45.7k
    bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr);
69
45.7k
}
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::PackVmlinuxBase(InputFile*, unsigned int, unsigned int, unsigned int, char const*)
Line
Count
Source
62
45.7k
    super(f),
63
45.7k
    my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata),
64
45.7k
    my_boot_label(boot_label),
65
45.7k
    n_ptload(0), phdri(nullptr), shdri(nullptr), shstrtab(nullptr)
66
45.7k
{
67
45.7k
    ElfClass::compileTimeAssertions();
68
45.7k
    bele = N_BELE_CTP::getRTP((const BeLePolicy*) nullptr);
69
45.7k
}
70
71
template <class T>
72
PackVmlinuxBase<T>::~PackVmlinuxBase()
73
137k
{
74
137k
    delete [] phdri;
75
137k
    delete [] shdri;
76
137k
    delete [] shstrtab;
77
137k
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::~PackVmlinuxBase()
Line
Count
Source
73
45.7k
{
74
45.7k
    delete [] phdri;
75
45.7k
    delete [] shdri;
76
45.7k
    delete [] shstrtab;
77
45.7k
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::~PackVmlinuxBase()
Line
Count
Source
73
45.7k
{
74
45.7k
    delete [] phdri;
75
45.7k
    delete [] shdri;
76
45.7k
    delete [] shstrtab;
77
45.7k
}
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::~PackVmlinuxBase()
Line
Count
Source
73
45.7k
{
74
45.7k
    delete [] phdri;
75
45.7k
    delete [] shdri;
76
45.7k
    delete [] shstrtab;
77
45.7k
}
78
79
template <class T>
80
int PackVmlinuxBase<T>::getStrategy(Filter &/*ft*/)
81
0
{
82
    // Called just before reading and compressing each block.
83
    // Might want to adjust blocksize, etc.
84
85
    // If user specified the filter, then use it (-2==strategy).
86
    // Else try the first two filters, and pick the better (2==strategy).
87
0
    return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
88
0
}
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::getStrategy(Filter&)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::getStrategy(Filter&)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::getStrategy(Filter&)
89
90
template <class T>
91
int __acc_cdecl_qsort
92
PackVmlinuxBase<T>::compare_Phdr(void const *aa, void const *bb)
93
0
{
94
0
    Phdr const *const a = (Phdr const *)aa;
95
0
    Phdr const *const b = (Phdr const *)bb;
96
0
    unsigned const xa = a->p_type - Phdr::PT_LOAD;
97
0
    unsigned const xb = b->p_type - Phdr::PT_LOAD;
98
0
            if (xa < xb)         return -1;  // PT_LOAD first
99
0
            if (xa > xb)         return  1;
100
0
    if (a->p_paddr < b->p_paddr) return -1;  // ascending by .p_paddr
101
0
    if (a->p_paddr > b->p_paddr) return  1;
102
    // What could remain?
103
    // try to make sort order deterministic and just compare more fields
104
0
#define CMP(field) \
105
0
    if (a->field != b->field) return a->field < b->field ? -1 : 1
106
0
    CMP(p_offset);
107
0
    CMP(p_vaddr);
108
0
    CMP(p_filesz);
109
0
    CMP(p_memsz);
110
0
    CMP(p_flags);
111
0
    CMP(p_align);
112
0
#undef CMP
113
0
    return 0;
114
0
}
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::compare_Phdr(void const*, void const*)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::compare_Phdr(void const*, void const*)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::compare_Phdr(void const*, void const*)
115
116
template <class T>
117
typename T::Shdr const *PackVmlinuxBase<T>::getElfSections()
118
1.73k
{
119
1.73k
    unsigned const e_shnum = ehdri.e_shnum;
120
1.73k
    if (ehdri.e_shentsize != sizeof(*shdri)
121
1.73k
    ||  file_size_u < ehdri.e_shoff
122
1.66k
    ||  file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) {
123
62
        infoWarning("bad ElfXX_Shdrs");
124
62
        return nullptr;
125
62
    }
126
1.66k
    shdri = new Shdr[(unsigned) e_shnum];
127
1.66k
    fi->seek(ehdri.e_shoff, SEEK_SET);
128
1.66k
    fi->readx(shdri, e_shnum * sizeof(*shdri));
129
1.66k
    unsigned const e_shstrndx = ehdri.e_shstrndx;
130
1.66k
    if (e_shnum <= e_shstrndx) {
131
52
        infoWarning("bad .e_shstrndx %#x", e_shstrndx);
132
52
        return nullptr;
133
52
    }
134
1.61k
    Shdr const *p = &shdri[e_shstrndx];
135
1.61k
    if (Shdr::SHT_STRTAB==p->sh_type
136
1.42k
    &&  p->sh_offset  <= (file_size_u - sizeof(*shdri))
137
1.21k
    &&  p->sh_size    <= (file_size_u - p->sh_offset)
138
1.04k
    &&  p->sh_name    <= (file_size_u - p->sh_offset)
139
970
    &&  10            <= (file_size_u - p->sh_name)
140
        // 10 == (1+ strlen(".shstrtab"))
141
1.61k
    ) {
142
956
        if (p->sh_size <= p->sh_name) {
143
48
            infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx);
144
48
            return nullptr;
145
48
        }
146
908
        shstrtab = new char[1+ p->sh_size];
147
908
        fi->seek(p->sh_offset, SEEK_SET);
148
908
        fi->readx(shstrtab, p->sh_size);
149
908
        shstrtab[p->sh_size] = '\0';
150
908
        if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {
151
653
            return p;
152
653
        }
153
908
    }
154
916
    return nullptr;
155
1.61k
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::getElfSections()
Line
Count
Source
118
462
{
119
462
    unsigned const e_shnum = ehdri.e_shnum;
120
462
    if (ehdri.e_shentsize != sizeof(*shdri)
121
462
    ||  file_size_u < ehdri.e_shoff
122
462
    ||  file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) {
123
0
        infoWarning("bad ElfXX_Shdrs");
124
0
        return nullptr;
125
0
    }
126
462
    shdri = new Shdr[(unsigned) e_shnum];
127
462
    fi->seek(ehdri.e_shoff, SEEK_SET);
128
462
    fi->readx(shdri, e_shnum * sizeof(*shdri));
129
462
    unsigned const e_shstrndx = ehdri.e_shstrndx;
130
462
    if (e_shnum <= e_shstrndx) {
131
22
        infoWarning("bad .e_shstrndx %#x", e_shstrndx);
132
22
        return nullptr;
133
22
    }
134
440
    Shdr const *p = &shdri[e_shstrndx];
135
440
    if (Shdr::SHT_STRTAB==p->sh_type
136
369
    &&  p->sh_offset  <= (file_size_u - sizeof(*shdri))
137
360
    &&  p->sh_size    <= (file_size_u - p->sh_offset)
138
325
    &&  p->sh_name    <= (file_size_u - p->sh_offset)
139
296
    &&  10            <= (file_size_u - p->sh_name)
140
        // 10 == (1+ strlen(".shstrtab"))
141
440
    ) {
142
291
        if (p->sh_size <= p->sh_name) {
143
16
            infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx);
144
16
            return nullptr;
145
16
        }
146
275
        shstrtab = new char[1+ p->sh_size];
147
275
        fi->seek(p->sh_offset, SEEK_SET);
148
275
        fi->readx(shstrtab, p->sh_size);
149
275
        shstrtab[p->sh_size] = '\0';
150
275
        if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {
151
195
            return p;
152
195
        }
153
275
    }
154
229
    return nullptr;
155
440
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::getElfSections()
Line
Count
Source
118
442
{
119
442
    unsigned const e_shnum = ehdri.e_shnum;
120
442
    if (ehdri.e_shentsize != sizeof(*shdri)
121
442
    ||  file_size_u < ehdri.e_shoff
122
442
    ||  file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) {
123
0
        infoWarning("bad ElfXX_Shdrs");
124
0
        return nullptr;
125
0
    }
126
442
    shdri = new Shdr[(unsigned) e_shnum];
127
442
    fi->seek(ehdri.e_shoff, SEEK_SET);
128
442
    fi->readx(shdri, e_shnum * sizeof(*shdri));
129
442
    unsigned const e_shstrndx = ehdri.e_shstrndx;
130
442
    if (e_shnum <= e_shstrndx) {
131
13
        infoWarning("bad .e_shstrndx %#x", e_shstrndx);
132
13
        return nullptr;
133
13
    }
134
429
    Shdr const *p = &shdri[e_shstrndx];
135
429
    if (Shdr::SHT_STRTAB==p->sh_type
136
361
    &&  p->sh_offset  <= (file_size_u - sizeof(*shdri))
137
342
    &&  p->sh_size    <= (file_size_u - p->sh_offset)
138
331
    &&  p->sh_name    <= (file_size_u - p->sh_offset)
139
321
    &&  10            <= (file_size_u - p->sh_name)
140
        // 10 == (1+ strlen(".shstrtab"))
141
429
    ) {
142
318
        if (p->sh_size <= p->sh_name) {
143
11
            infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx);
144
11
            return nullptr;
145
11
        }
146
307
        shstrtab = new char[1+ p->sh_size];
147
307
        fi->seek(p->sh_offset, SEEK_SET);
148
307
        fi->readx(shstrtab, p->sh_size);
149
307
        shstrtab[p->sh_size] = '\0';
150
307
        if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {
151
220
            return p;
152
220
        }
153
307
    }
154
198
    return nullptr;
155
429
}
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::getElfSections()
Line
Count
Source
118
827
{
119
827
    unsigned const e_shnum = ehdri.e_shnum;
120
827
    if (ehdri.e_shentsize != sizeof(*shdri)
121
827
    ||  file_size_u < ehdri.e_shoff
122
765
    ||  file_size_u < ehdri.e_shoff + mem_size(ehdri.e_shentsize, e_shnum)) {
123
62
        infoWarning("bad ElfXX_Shdrs");
124
62
        return nullptr;
125
62
    }
126
765
    shdri = new Shdr[(unsigned) e_shnum];
127
765
    fi->seek(ehdri.e_shoff, SEEK_SET);
128
765
    fi->readx(shdri, e_shnum * sizeof(*shdri));
129
765
    unsigned const e_shstrndx = ehdri.e_shstrndx;
130
765
    if (e_shnum <= e_shstrndx) {
131
17
        infoWarning("bad .e_shstrndx %#x", e_shstrndx);
132
17
        return nullptr;
133
17
    }
134
748
    Shdr const *p = &shdri[e_shstrndx];
135
748
    if (Shdr::SHT_STRTAB==p->sh_type
136
693
    &&  p->sh_offset  <= (file_size_u - sizeof(*shdri))
137
508
    &&  p->sh_size    <= (file_size_u - p->sh_offset)
138
385
    &&  p->sh_name    <= (file_size_u - p->sh_offset)
139
353
    &&  10            <= (file_size_u - p->sh_name)
140
        // 10 == (1+ strlen(".shstrtab"))
141
748
    ) {
142
347
        if (p->sh_size <= p->sh_name) {
143
21
            infoWarning("bad .shstrtab _Shdr[%u]", (unsigned)ehdri.e_shstrndx);
144
21
            return nullptr;
145
21
        }
146
326
        shstrtab = new char[1+ p->sh_size];
147
326
        fi->seek(p->sh_offset, SEEK_SET);
148
326
        fi->readx(shstrtab, p->sh_size);
149
326
        shstrtab[p->sh_size] = '\0';
150
326
        if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {
151
238
            return p;
152
238
        }
153
326
    }
154
489
    return nullptr;
155
748
}
156
157
template <class T>
158
tribool PackVmlinuxBase<T>::canPack()
159
0
{
160
0
    fi->seek(0, SEEK_SET);
161
0
    fi->readx(&ehdri, sizeof(ehdri));
162
163
    // now check the ELF header
164
0
    if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4)
165
0
    ||  ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass
166
0
    ||  ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata
167
0
    ||  ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT
168
0
    ||  !memcmp(&ehdri.e_ident[8], "FreeBSD", 7)  // branded
169
0
    ||  ehdri.e_machine != my_e_machine
170
0
    ||  ehdri.e_version != 1  // version
171
0
    ||  ehdri.e_ehsize != sizeof(ehdri)  // different <elf.h> ?
172
0
    ) {
173
0
        return false;
174
0
    }
175
176
    // additional requirements for vmlinux
177
0
    if (ehdri.e_type != Ehdr::ET_EXEC
178
0
    ||  ehdri.e_phoff != sizeof(ehdri)  // Phdr not contiguous with Ehdr
179
0
    ||  ehdri.e_phentsize!=sizeof(Phdr)
180
0
    ||  !is_valid_e_entry(ehdri.e_entry)
181
0
    ) {
182
0
        return false;
183
0
    }
184
185
    // A Linux kernel must have a __ksymtab section. [??]
186
0
    Shdr const *p, *const shstrsec = getElfSections();
187
0
    if (nullptr==shstrsec) {
188
0
        return false;
189
0
    }
190
0
    {
191
0
        int j;
192
0
        for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) {
193
0
            if (Shdr::SHT_PROGBITS==p->sh_type
194
0
            && p->sh_name < shstrsec->sh_size
195
0
            && 0==strcmp("__ksymtab", p->sh_name + shstrtab)) {
196
0
                break;
197
0
            }
198
0
        }
199
0
        if (j < 0) {
200
0
            return false;
201
0
        }
202
0
    }
203
204
0
    phdri = new Phdr[(unsigned) ehdri.e_phnum];
205
0
    fi->seek(ehdri.e_phoff, SEEK_SET);
206
0
    fi->readx(phdri, ehdri.e_phnum * sizeof(*phdri));
207
208
    // Put PT_LOAD together at the beginning, ascending by .p_paddr.
209
0
    upx_qsort(phdri, ehdri.e_phnum, sizeof(*phdri), compare_Phdr);
210
211
    // Find convex hull of physical addresses, and count the PT_LOAD.
212
    // Ignore ".bss": .p_filesz < .p_memsz
213
0
    unsigned phys_lo= ~0u, phys_hi= 0u;
214
0
    for (unsigned j = 0; j < ehdri.e_phnum; ++j) {
215
0
        if (Phdr::PT_LOAD==phdri[j].p_type) {
216
            // Check for general sanity (not necessarily required.)
217
0
            if (0xfff & (phdri[j].p_offset | phdri[j].p_paddr
218
0
                       | phdri[j].p_align  | phdri[j].p_vaddr) ) {
219
0
                return false;
220
0
            }
221
0
            if (phys_lo > phdri[j].p_paddr) {
222
0
                phys_lo = phdri[j].p_paddr;
223
0
            }
224
0
            if (phys_hi < (phdri[j].p_filesz + phdri[j].p_paddr)) {
225
0
                phys_hi = (phdri[j].p_filesz + phdri[j].p_paddr);
226
0
            }
227
0
            ++n_ptload;
228
0
        }
229
0
    }
230
0
    paddr_min = phys_lo;
231
0
    sz_ptload = phys_hi - phys_lo;
232
0
    return 0 < n_ptload;
233
0
}
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::canPack()
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::canPack()
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::canPack()
234
235
#include "p_elf.h"
236
237
template <class T>
238
void PackVmlinuxBase<T>::pack(OutputFile *fo)
239
0
{
240
0
    unsigned fo_off = 0;
241
0
    Ehdr ehdro;
242
0
    TE32 tmp_u32;
243
244
    // nullptr
245
    // .text(PT_LOADs) .note(1st page) .note(rest)
246
    // .shstrtab .symtab .strtab
247
0
    Shdr shdro[1+3+3];
248
0
    memset(shdro, 0, sizeof(shdro));
249
250
0
    ibuf.alloc(file_size);
251
0
    obuf.allocForCompression(file_size);
252
253
    // .e_ident, .e_machine, .e_version, .e_flags
254
0
    memcpy(&ehdro, &ehdri, sizeof(ehdro));
255
0
    ehdro.e_type = Ehdr::ET_REL;
256
0
    ehdro.e_entry = 0;
257
0
    ehdro.e_phoff = 0;
258
0
    ehdro.e_shoff = sizeof(ehdro);
259
0
    ehdro.e_phentsize = 0;
260
0
    ehdro.e_phnum = 0;
261
0
    ehdro.e_shnum = 1+3+3;
262
0
    ehdro.e_shstrndx = 4;
263
0
    fo->write(&ehdro, sizeof(ehdro)); fo_off+= sizeof(ehdro);
264
0
    fo->write(shdro, sizeof(shdro)); fo_off+= sizeof(shdro);
265
266
// Notice overlap [containment] of physical PT_LOAD[2] into PTLOAD[1]
267
// in this vmlinux for x86_64 from Fedora Core 6 on 2007-01-07:
268
//Program Headers:
269
//  Type           Offset             VirtAddr           PhysAddr
270
//                 FileSiz            MemSiz              Flags  Align
271
//  LOAD           0x0000000000200000 0xffffffff80200000 0x0000000000200000
272
//                 0x000000000034bce8 0x000000000034bce8  R E    200000
273
//  LOAD           0x000000000054c000 0xffffffff8054c000 0x000000000054c000
274
//                 0x00000000000ed004 0x00000000001702a4  RWE    200000
275
//  LOAD           0x0000000000800000 0xffffffffff600000 0x00000000005f5000
276
//                 0x0000000000000c08 0x0000000000000c08  RWE    200000
277
//  NOTE           0x0000000000000000 0x0000000000000000 0x0000000000000000
278
//                 0x0000000000000000 0x0000000000000000  R      8
279
// Therefore we must "compose" the convex hull to be loaded.
280
281
0
    ph.u_len = sz_ptload;
282
0
    memset(ibuf, 0, sz_ptload);
283
0
    for (unsigned j = 0; j < ehdri.e_phnum; ++j) {
284
0
        if (Phdr::PT_LOAD==phdri[j].p_type) {
285
0
            fi->seek(phdri[j].p_offset, SEEK_SET);
286
0
            fi->readx(ibuf + ((unsigned) phdri[j].p_paddr - paddr_min), phdri[j].p_filesz);
287
0
        }
288
0
    }
289
0
    checkAlreadyPacked(ibuf + (ph.u_len - 1024), 1024);
290
291
    // prepare filter
292
0
    ph.filter = 0;
293
0
    Filter ft(ph.level);
294
0
    ft.buf_len = ph.u_len;
295
0
    ft.addvalue = 0;  // we are independent of actual runtime address; see ckt32
296
297
0
    upx_compress_config_t cconf; cconf.reset();
298
    // limit stack size needed for runtime decompression
299
0
    cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
300
301
0
    unsigned ppc32_extra = 0;
302
0
    if (Ehdr::EM_PPC==my_e_machine) {
303
        // output layout:
304
        //      .long UPX_MAGIC_LE32
305
        //      .long L20 - L10
306
        // L10:
307
        //      b_info for Ehdr; compressed Ehdr; .balign 4  // one block only
308
        //      b_info for LOAD; compressed LOAD; .balign 4  // possibly many blocks
309
        //          // This allows per-block filters!
310
        // L20:
311
        //      b f_decompress
312
        // +4:  f_unfilter(char *buf, unsigned len, unsigned cto8, unsigned ftid)
313
        //          // Code for multiple filters can "daisy chain" on ftid.
314
        //      f_decompress(char const *src, unsigned  src_len,
315
        //                   char       *dst, unsigned *dst_len, int method)
316
0
        unsigned tmp;
317
0
        tmp = UPX_MAGIC_LE32; fo->write(&tmp, sizeof(tmp)); fo_off += sizeof(tmp);
318
0
        tmp = 0;              fo->write(&tmp, sizeof(tmp)); fo_off += sizeof(tmp);
319
0
        ppc32_extra += 2*sizeof(tmp);
320
0
        unsigned const len_unc = sizeof(ehdri) + sizeof(Phdr) * ehdri.e_phnum;
321
0
        MemBuffer unc_hdr(len_unc);
322
0
        MemBuffer cpr_hdr; cpr_hdr.allocForCompression(len_unc);
323
0
        memcpy(&unc_hdr[0],             &ehdri, sizeof(ehdri));
324
0
        memcpy(&unc_hdr[sizeof(ehdri)],  phdri, sizeof(Phdr) * ehdri.e_phnum);
325
0
        unsigned len_cpr = 0;
326
0
        int const r = upx_compress(unc_hdr, len_unc, cpr_hdr, &len_cpr,
327
0
            nullptr, ph.method, 10, nullptr, nullptr );
328
0
        if (UPX_E_OK!=r || len_unc<=len_cpr)  // FIXME: allow no compression
329
0
            throwInternalError("Ehdr compression failed");
330
331
0
        packed_struct(b_info) { // 12-byte header before each compressed block
332
0
            NE32 sz_unc;  // uncompressed_size
333
0
            NE32 sz_cpr;  //   compressed_size
334
0
            unsigned char b_method;  // compression algorithm
335
0
            unsigned char b_ftid;  // filter id
336
0
            unsigned char b_cto8;  // filter parameter
337
0
            unsigned char b_unused;  // FIXME: !=0  for partial-block unfilter
338
            // NE32 f_offset, f_len;  // only if    partial-block unfilter
339
0
        };
340
341
0
        struct b_info hdr_info;
342
0
        set_be32(&hdr_info.sz_unc, len_unc);
343
0
        set_be32(&hdr_info.sz_cpr, len_cpr);
344
0
        hdr_info.b_method = ph.method;
345
0
        hdr_info.b_ftid = 0;
346
0
        hdr_info.b_cto8 = 0;
347
0
        hdr_info.b_unused = 0;
348
0
        fo->write(&hdr_info, sizeof(hdr_info)); fo_off += sizeof(hdr_info);
349
0
        unsigned const frag = (3& (0u-len_cpr));
350
0
        ppc32_extra += sizeof(hdr_info) + len_cpr + frag;
351
0
        fo_off += len_cpr + frag;
352
0
        memset(&cpr_hdr[len_cpr], 0, frag);  // valgrind only
353
0
        fo->write(cpr_hdr, len_cpr + frag);
354
355
        // Partial filter: .text and following contiguous SHF_EXECINSTR
356
0
        upx_bytep f_ptr = ibuf;
357
0
        unsigned  f_len = 0;
358
0
        Shdr const *shdr = 1+ shdri;  // skip empty shdr[0]
359
0
        if (ft.buf_len==0  // not specified yet  FIXME: was set near construction
360
0
        && (Shdr::SHF_ALLOC     & shdr->sh_flags)
361
0
        && (Shdr::SHF_EXECINSTR & shdr->sh_flags)) {
362
            // shdr[1] is instructions (probably .text)
363
0
            f_ptr = ibuf + (unsigned) (shdr->sh_offset - phdri[0].p_offset);
364
0
            f_len = shdr->sh_size;
365
0
            ++shdr;
366
0
            for (int j= ehdri.e_shnum - 2; --j>=0; ++shdr) {
367
0
                unsigned prev_end = shdr[-1].sh_size + shdr[-1].sh_offset;
368
0
                prev_end += ~(0u-shdr[0].sh_addralign) & (0u-prev_end);  // align_up
369
0
                if ((Shdr::SHF_ALLOC     & shdr->sh_flags)
370
0
                &&  (Shdr::SHF_EXECINSTR & shdr->sh_flags)
371
0
                &&  shdr[0].sh_offset==prev_end) {
372
0
                    f_len += shdr->sh_size;
373
0
                }
374
0
                else {
375
0
                    break;
376
0
                }
377
0
            }
378
0
        }
379
0
        else { // ft.buf_len already specified, or Shdr[1] not instructions
380
0
            f_ptr = ibuf;
381
0
            f_len = ph.u_len;
382
0
        }
383
0
        compressWithFilters(ibuf, ph.u_len, obuf,
384
0
            f_ptr, f_len,  // filter range
385
0
            nullptr, 0,  // hdr_ptr, hdr_len
386
0
            &ft, 512, &cconf, getStrategy(ft));
387
388
0
        set_be32(&hdr_info.sz_unc, ph.u_len);
389
0
        set_be32(&hdr_info.sz_cpr, ph.c_len);
390
0
        hdr_info.b_ftid = ft.id;
391
0
        hdr_info.b_cto8 = ft.cto;
392
0
        if (ph.u_len!=f_len) {
393
0
            hdr_info.b_unused = 1;  // flag for partial filter
394
0
        }
395
0
        fo->write(&hdr_info, sizeof(hdr_info)); fo_off += sizeof(hdr_info);
396
0
        ppc32_extra += sizeof(hdr_info);
397
0
        if (ph.u_len!=f_len) {
398
0
            set_be32(&hdr_info.sz_unc, f_ptr - (upx_bytep) ibuf);
399
0
            set_be32(&hdr_info.sz_cpr, f_len);
400
0
            fo->write(&hdr_info, 2*sizeof(unsigned)); fo_off += 2*sizeof(unsigned);
401
0
            ppc32_extra += 2*sizeof(unsigned);
402
0
        }
403
0
    }
404
0
    else {
405
0
        compressWithFilters(&ft, 512, &cconf, getStrategy(ft));
406
0
    }
407
0
    unsigned const txt_c_len = ph.c_len;
408
409
0
    const unsigned lsize = getLoaderSize();
410
411
0
    defineDecompressorSymbols();
412
0
    defineFilterSymbols(&ft);
413
0
    relocateLoader();
414
415
0
    MemBuffer loader(lsize);
416
0
    memcpy(loader, getLoader(), lsize);
417
0
    patchPackHeader(loader, lsize);
418
419
0
#define shstrtab local_shstrtab // avoid -Wshadow warning
420
0
    char const shstrtab[]= "\0.text\0.note\0.shstrtab\0.symtab\0.strtab";
421
0
    char const *p = shstrtab;
422
0
    while (0!=*p++) ;
423
0
    shdro[1].sh_name = ptr_diff(p, shstrtab);
424
0
    shdro[1].sh_type = Shdr::SHT_PROGBITS;
425
0
    shdro[1].sh_flags = Shdr::SHF_ALLOC | Shdr::SHF_EXECINSTR;
426
0
    shdro[1].sh_offset = fo_off - ppc32_extra;
427
0
    shdro[1].sh_size = ppc32_extra + txt_c_len + lsize;  // plus more ...
428
0
    shdro[1].sh_addralign = 1;  // default
429
430
0
    fo_off += write_vmlinux_head(fo, &shdro[1]);
431
0
    fo->write(obuf, txt_c_len); fo_off += txt_c_len;
432
0
    unsigned const a = (shdro[1].sh_addralign -1) & (0u-(ppc32_extra + txt_c_len));
433
0
    if (0!=a) { // align
434
0
        fo_off += a;
435
0
        shdro[1].sh_size += a;
436
0
        fo->seek(a, SEEK_CUR);
437
0
    }
438
0
    fo->write(loader, lsize); fo_off += lsize;
439
440
#if 0
441
    printf("%-13s: compressed   : %8u bytes\n", getName(), txt_c_len);
442
    printf("%-13s: decompressor : %8u bytes\n", getName(), lsize);
443
#endif
444
0
    verifyOverlappingDecompression();
445
446
    // .note with 1st page --------------------------------
447
0
    ph.u_len = phdri[0].p_offset;
448
0
    fi->seek(0, SEEK_SET);
449
0
    fi->readx(ibuf, ph.u_len);
450
0
    compress(ibuf, ph.u_len, obuf, &cconf);
451
452
0
    while (0!=*p++) ;
453
0
    shdro[2].sh_name = ptr_diff(p, shstrtab);
454
0
    shdro[2].sh_type = Shdr::SHT_NOTE;
455
0
    shdro[2].sh_offset = fo_off;
456
0
    shdro[2].sh_size = sizeof(ph.u_len) + ph.c_len;
457
0
    shdro[2].sh_addralign = 1;
458
0
    tmp_u32 = ph.u_len; fo->write(&tmp_u32, 4);
459
0
    fo->write(obuf, ph.c_len); fo_off += shdro[2].sh_size;
460
461
    // .note with rest     --------------------------------
462
0
    ph.u_len = file_size - (sz_ptload + phdri[0].p_offset);
463
0
    fi->seek(sz_ptload + phdri[0].p_offset, SEEK_SET);
464
0
    fi->readx(ibuf, ph.u_len);
465
466
    // Temporarily decrease ph.level by about (1+ log2(sz_rest / sz_ptload))
467
    // to avoid spending unreasonable effort compressing large symbol tables
468
    // that are discarded 99.9% of the time anyway.
469
0
    int const old_level = ph.level;
470
0
    for (unsigned v = ((ph.u_len>>3) + ph.u_len) / sz_ptload; 0 < v; v>>=1) {
471
0
        if (0== --ph.level) {
472
0
            ph.level = 1;
473
0
        }
474
0
    }
475
0
    compress(ibuf, ph.u_len, obuf, &cconf);
476
0
    ph.level = old_level;
477
478
    // while (0!=*p++) ;  // name is the same
479
0
    shdro[3].sh_name = ptr_diff(p, shstrtab);
480
0
    shdro[3].sh_type = Shdr::SHT_NOTE;
481
0
    shdro[3].sh_offset = fo_off;
482
0
    shdro[3].sh_size = sizeof(ph.u_len) + ph.c_len;
483
0
    shdro[3].sh_addralign = 1;
484
0
    tmp_u32 = ph.u_len; fo->write(&tmp_u32, 4);
485
0
    fo->write(obuf, ph.c_len); fo_off += shdro[3].sh_size;
486
487
0
    while (0!=*p++) ;
488
0
    shdro[4].sh_name = ptr_diff(p, shstrtab);
489
0
    shdro[4].sh_type = Shdr::SHT_STRTAB;
490
0
    shdro[4].sh_offset = fo_off;
491
0
    shdro[4].sh_size = sizeof(shstrtab);  // already includes terminating '\0'
492
0
    shdro[4].sh_addralign = 1;
493
0
    fo->write(shstrtab, shdro[4].sh_size); fo_off += shdro[4].sh_size;
494
495
0
    fo_off = ~3 & (3+ fo_off); fo->seek(fo_off, SEEK_SET);
496
0
    while (0!=*p++) ;
497
0
    shdro[5].sh_name = ptr_diff(p, shstrtab);
498
0
    shdro[5].sh_type = Shdr::SHT_SYMTAB;
499
0
    shdro[5].sh_offset = fo_off;
500
0
    shdro[5].sh_size = ((Ehdr::EM_PPC==my_e_machine) + 5)*sizeof(Sym);
501
    //shdro[5].sh_flags = Shdr::SHF_INFO_LINK;
502
0
    shdro[5].sh_link = 6;  // to .strtab for symbols
503
0
    shdro[5].sh_info = 1+3;  // number of non-global symbols [binutils/bfd/elf.c]
504
0
    shdro[5].sh_addralign = 4;
505
0
    shdro[5].sh_entsize = sizeof(Sym);
506
507
0
    Sym sec_sym;
508
509
    // Symbol 0; no references, but bfd demands it.
510
0
    memset(&sec_sym, 0, sizeof(sec_sym));
511
0
    fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym);
512
513
    // Each section before .shstrtab needs a symbol.
514
0
    sec_sym.st_info = sec_sym.make_st_info(Sym::STB_LOCAL, Sym::STT_SECTION);
515
0
    sec_sym.st_other = Sym::STV_DEFAULT;
516
0
    sec_sym.st_shndx = 1;  // .text
517
0
    fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym);
518
0
    sec_sym.st_shndx = 2;  // .note
519
0
    fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym);
520
0
    sec_sym.st_shndx = 3;  // .note
521
0
    fo->write(&sec_sym, sizeof(sec_sym)); fo_off += sizeof(sec_sym);
522
523
    // the symbol we care about
524
0
    Sym unc_ker;
525
0
    unc_ker.st_name = 1;  // 1 byte into strtab
526
0
    unc_ker.st_value = 0;
527
0
    unc_ker.st_size = ppc32_extra + txt_c_len;
528
0
    unc_ker.st_info = unc_ker.make_st_info(Sym::STB_GLOBAL, Sym::STT_FUNC);
529
0
    unc_ker.st_other = Sym::STV_DEFAULT;
530
0
    unc_ker.st_shndx = 1;  // .text
531
0
    fo->write(&unc_ker, sizeof(unc_ker)); fo_off += sizeof(unc_ker);
532
533
0
    unsigned const lablen = strlen(my_boot_label);
534
0
    if (Ehdr::EM_PPC==my_e_machine) {
535
0
        unc_ker.st_name += 1+ lablen;
536
0
        unc_ker.st_value = unc_ker.st_size;
537
0
        unc_ker.st_size = 0;
538
0
        fo->write(&unc_ker, sizeof(unc_ker)); fo_off += sizeof(unc_ker);
539
0
    }
540
0
    while (0!=*p++) ;
541
0
    shdro[6].sh_name = ptr_diff(p, shstrtab);
542
0
    shdro[6].sh_type = Shdr::SHT_STRTAB;
543
0
    shdro[6].sh_offset = fo_off;
544
0
    shdro[6].sh_size = 2+ lablen + (Ehdr::EM_PPC==my_e_machine)*(1+ 12);  // '\0' before and after
545
0
    shdro[6].sh_addralign = 1;
546
0
    fo->seek(1, SEEK_CUR);  // the '\0' before
547
0
    fo->write(my_boot_label, 1+ lablen);  // include the '\0' terminator
548
0
    if (Ehdr::EM_PPC==my_e_machine) {
549
0
        fo->write("_vmlinux_end", 1+ 12); fo_off += 1+ 12;
550
0
    }
551
0
    fo_off += 2+ lablen;
552
553
0
    fo->seek(0, SEEK_SET);
554
0
    fo->write(&ehdro, sizeof(ehdro));
555
0
    fo->write(&shdro[0], sizeof(shdro));
556
0
    if (Ehdr::EM_PPC==my_e_machine) {
557
0
        fo->seek(sizeof(unsigned), SEEK_CUR);
558
0
        set_be32(&ppc32_extra, ppc32_extra - 2*sizeof(unsigned) + txt_c_len);
559
0
        fo->write(&ppc32_extra, sizeof(ppc32_extra));
560
0
    }
561
562
0
    if (!checkFinalCompressionRatio(fo))
563
0
        throwNotCompressible();
564
0
#undef shstrtab
565
0
}
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::pack(OutputFile*)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::pack(OutputFile*)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::pack(OutputFile*)
566
567
template <class T>
568
tribool PackVmlinuxBase<T>::canUnpack()
569
137k
{
570
137k
    fi->seek(0, SEEK_SET);
571
137k
    fi->readx(&ehdri, sizeof(ehdri));
572
573
    // now check the ELF header
574
137k
    if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4)
575
81.4k
    ||  ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass
576
40.1k
    ||  ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata
577
19.5k
    ||  ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT
578
18.5k
    ||  !memcmp(&ehdri.e_ident[8], "FreeBSD", 7)  // branded
579
18.4k
    ||  ehdri.e_machine != my_e_machine
580
6.81k
    ||  ehdri.e_version != 1  // version
581
6.08k
    ||  ehdri.e_ehsize != sizeof(ehdri)  // different <elf.h> ?
582
137k
    )
583
131k
        return false;
584
585
5.44k
    if (ehdri.e_type != Ehdr::ET_REL
586
    //i386 fails  ||  ehdri.e_shoff != sizeof(ehdri)  // Shdr not contiguous with Ehdr
587
2.04k
    ||  ehdri.e_shentsize!=sizeof(Shdr)
588
1.99k
    ||  ehdri.e_shnum < 4
589
1.97k
    ||  (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff)
590
5.44k
    )
591
3.71k
        return false;
592
593
    // find the .shstrtab section
594
1.73k
    Shdr const *const shstrsec = getElfSections();
595
1.73k
    if (nullptr==shstrsec) {
596
1.07k
        return false;
597
1.07k
    }
598
599
    // check for .text .note .note  and sane (.sh_size + .sh_offset)
600
653
    p_note0 = p_note1 = p_text = nullptr;
601
653
    int j;
602
653
    Shdr *p;
603
103k
    for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) {
604
103k
        if ((unsigned)file_size < (p->sh_size + p->sh_offset)
605
35.2k
        || (5+ p->sh_name) < p->sh_name  // wrap: ignore malformed
606
80.1k
        ||  shstrsec->sh_size < (5+ p->sh_name) ) {
607
80.1k
            continue;
608
80.1k
        }
609
23.1k
        if (0==strcmp(".text", shstrtab + p->sh_name)) {
610
1.21k
            p_text = p;
611
1.21k
        }
612
23.1k
        if (0==strcmp(".note", shstrtab + p->sh_name)) {
613
1.15k
            if (nullptr==p_note0) {
614
108
                p_note0 = p;
615
108
            } else
616
1.04k
            if (nullptr==p_note1) {
617
82
                p_note1 = p;
618
82
            }
619
1.15k
        }
620
23.1k
    }
621
653
    if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) {
622
621
        return false;
623
621
    }
624
625
32
    char buf[1024];
626
32
    fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET);
627
32
    fi->readx(buf, sizeof(buf));
628
32
    if (!getPackHeader(buf, sizeof(buf)))
629
12
        return -1; // format is known, but definitely is not packed
630
631
20
    return true;
632
32
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::canUnpack()
Line
Count
Source
569
45.7k
{
570
45.7k
    fi->seek(0, SEEK_SET);
571
45.7k
    fi->readx(&ehdri, sizeof(ehdri));
572
573
    // now check the ELF header
574
45.7k
    if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4)
575
27.1k
    ||  ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass
576
13.1k
    ||  ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata
577
4.91k
    ||  ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT
578
4.59k
    ||  !memcmp(&ehdri.e_ident[8], "FreeBSD", 7)  // branded
579
4.57k
    ||  ehdri.e_machine != my_e_machine
580
1.33k
    ||  ehdri.e_version != 1  // version
581
1.17k
    ||  ehdri.e_ehsize != sizeof(ehdri)  // different <elf.h> ?
582
45.7k
    )
583
44.6k
        return false;
584
585
1.04k
    if (ehdri.e_type != Ehdr::ET_REL
586
    //i386 fails  ||  ehdri.e_shoff != sizeof(ehdri)  // Shdr not contiguous with Ehdr
587
531
    ||  ehdri.e_shentsize!=sizeof(Shdr)
588
524
    ||  ehdri.e_shnum < 4
589
519
    ||  (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff)
590
1.04k
    )
591
587
        return false;
592
593
    // find the .shstrtab section
594
462
    Shdr const *const shstrsec = getElfSections();
595
462
    if (nullptr==shstrsec) {
596
267
        return false;
597
267
    }
598
599
    // check for .text .note .note  and sane (.sh_size + .sh_offset)
600
195
    p_note0 = p_note1 = p_text = nullptr;
601
195
    int j;
602
195
    Shdr *p;
603
25.1k
    for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) {
604
24.9k
        if ((unsigned)file_size < (p->sh_size + p->sh_offset)
605
10.2k
        || (5+ p->sh_name) < p->sh_name  // wrap: ignore malformed
606
18.0k
        ||  shstrsec->sh_size < (5+ p->sh_name) ) {
607
18.0k
            continue;
608
18.0k
        }
609
6.87k
        if (0==strcmp(".text", shstrtab + p->sh_name)) {
610
450
            p_text = p;
611
450
        }
612
6.87k
        if (0==strcmp(".note", shstrtab + p->sh_name)) {
613
369
            if (nullptr==p_note0) {
614
39
                p_note0 = p;
615
39
            } else
616
330
            if (nullptr==p_note1) {
617
32
                p_note1 = p;
618
32
            }
619
369
        }
620
6.87k
    }
621
195
    if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) {
622
182
        return false;
623
182
    }
624
625
13
    char buf[1024];
626
13
    fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET);
627
13
    fi->readx(buf, sizeof(buf));
628
13
    if (!getPackHeader(buf, sizeof(buf)))
629
5
        return -1; // format is known, but definitely is not packed
630
631
8
    return true;
632
13
}
PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::canUnpack()
Line
Count
Source
569
45.7k
{
570
45.7k
    fi->seek(0, SEEK_SET);
571
45.7k
    fi->readx(&ehdri, sizeof(ehdri));
572
573
    // now check the ELF header
574
45.7k
    if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4)
575
27.1k
    ||  ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass
576
13.1k
    ||  ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata
577
7.04k
    ||  ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT
578
6.76k
    ||  !memcmp(&ehdri.e_ident[8], "FreeBSD", 7)  // branded
579
6.74k
    ||  ehdri.e_machine != my_e_machine
580
2.80k
    ||  ehdri.e_version != 1  // version
581
2.50k
    ||  ehdri.e_ehsize != sizeof(ehdri)  // different <elf.h> ?
582
45.7k
    )
583
43.6k
        return false;
584
585
2.12k
    if (ehdri.e_type != Ehdr::ET_REL
586
    //i386 fails  ||  ehdri.e_shoff != sizeof(ehdri)  // Shdr not contiguous with Ehdr
587
488
    ||  ehdri.e_shentsize!=sizeof(Shdr)
588
467
    ||  ehdri.e_shnum < 4
589
460
    ||  (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff)
590
2.12k
    )
591
1.68k
        return false;
592
593
    // find the .shstrtab section
594
442
    Shdr const *const shstrsec = getElfSections();
595
442
    if (nullptr==shstrsec) {
596
222
        return false;
597
222
    }
598
599
    // check for .text .note .note  and sane (.sh_size + .sh_offset)
600
220
    p_note0 = p_note1 = p_text = nullptr;
601
220
    int j;
602
220
    Shdr *p;
603
39.0k
    for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) {
604
38.8k
        if ((unsigned)file_size < (p->sh_size + p->sh_offset)
605
16.2k
        || (5+ p->sh_name) < p->sh_name  // wrap: ignore malformed
606
28.3k
        ||  shstrsec->sh_size < (5+ p->sh_name) ) {
607
28.3k
            continue;
608
28.3k
        }
609
10.4k
        if (0==strcmp(".text", shstrtab + p->sh_name)) {
610
596
            p_text = p;
611
596
        }
612
10.4k
        if (0==strcmp(".note", shstrtab + p->sh_name)) {
613
470
            if (nullptr==p_note0) {
614
46
                p_note0 = p;
615
46
            } else
616
424
            if (nullptr==p_note1) {
617
29
                p_note1 = p;
618
29
            }
619
470
        }
620
10.4k
    }
621
220
    if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) {
622
208
        return false;
623
208
    }
624
625
12
    char buf[1024];
626
12
    fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET);
627
12
    fi->readx(buf, sizeof(buf));
628
12
    if (!getPackHeader(buf, sizeof(buf)))
629
5
        return -1; // format is known, but definitely is not packed
630
631
7
    return true;
632
12
}
PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::canUnpack()
Line
Count
Source
569
45.7k
{
570
45.7k
    fi->seek(0, SEEK_SET);
571
45.7k
    fi->readx(&ehdri, sizeof(ehdri));
572
573
    // now check the ELF header
574
45.7k
    if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4)
575
27.1k
    ||  ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass
576
13.7k
    ||  ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata
577
7.59k
    ||  ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT
578
7.20k
    ||  !memcmp(&ehdri.e_ident[8], "FreeBSD", 7)  // branded
579
7.17k
    ||  ehdri.e_machine != my_e_machine
580
2.68k
    ||  ehdri.e_version != 1  // version
581
2.39k
    ||  ehdri.e_ehsize != sizeof(ehdri)  // different <elf.h> ?
582
45.7k
    )
583
43.4k
        return false;
584
585
2.27k
    if (ehdri.e_type != Ehdr::ET_REL
586
    //i386 fails  ||  ehdri.e_shoff != sizeof(ehdri)  // Shdr not contiguous with Ehdr
587
1.02k
    ||  ehdri.e_shentsize!=sizeof(Shdr)
588
1.00k
    ||  ehdri.e_shnum < 4
589
998
    ||  (unsigned)file_size < (ehdri.e_shnum * sizeof(Shdr) + ehdri.e_shoff)
590
2.27k
    )
591
1.44k
        return false;
592
593
    // find the .shstrtab section
594
827
    Shdr const *const shstrsec = getElfSections();
595
827
    if (nullptr==shstrsec) {
596
589
        return false;
597
589
    }
598
599
    // check for .text .note .note  and sane (.sh_size + .sh_offset)
600
238
    p_note0 = p_note1 = p_text = nullptr;
601
238
    int j;
602
238
    Shdr *p;
603
39.6k
    for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) {
604
39.4k
        if ((unsigned)file_size < (p->sh_size + p->sh_offset)
605
8.78k
        || (5+ p->sh_name) < p->sh_name  // wrap: ignore malformed
606
33.6k
        ||  shstrsec->sh_size < (5+ p->sh_name) ) {
607
33.6k
            continue;
608
33.6k
        }
609
5.75k
        if (0==strcmp(".text", shstrtab + p->sh_name)) {
610
164
            p_text = p;
611
164
        }
612
5.75k
        if (0==strcmp(".note", shstrtab + p->sh_name)) {
613
311
            if (nullptr==p_note0) {
614
23
                p_note0 = p;
615
23
            } else
616
288
            if (nullptr==p_note1) {
617
21
                p_note1 = p;
618
21
            }
619
311
        }
620
5.75k
    }
621
238
    if (nullptr==p_text || nullptr==p_note0 || nullptr==p_note1) {
622
231
        return false;
623
231
    }
624
625
7
    char buf[1024];
626
7
    fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET);
627
7
    fi->readx(buf, sizeof(buf));
628
7
    if (!getPackHeader(buf, sizeof(buf)))
629
2
        return -1; // format is known, but definitely is not packed
630
631
5
    return true;
632
7
}
633
634
template <class T>
635
void PackVmlinuxBase<T>::unpack(OutputFile *fo)
636
0
{
637
0
    TE32 word;
638
0
    PackHeader const ph_tmp(ph);
639
640
0
    fi->seek(p_note0->sh_offset, SEEK_SET);
641
0
    fi->readx(&word, sizeof(word));
642
0
    ph.u_len = word;
643
0
    ph.c_len = p_note0->sh_size - sizeof(word);
644
0
    ibuf.alloc(ph.c_len);
645
0
    fi->readx(ibuf, ph.c_len);
646
0
    obuf.allocForDecompression(ph.u_len);
647
0
    decompress(ibuf, obuf, false);
648
0
    fo->write(obuf, ph.u_len);
649
0
    obuf.dealloc();
650
0
    ibuf.dealloc();
651
652
0
    ph = ph_tmp;
653
0
    if (!has_valid_vmlinux_head()) {
654
0
        throwCantUnpack(".text corrupted");
655
0
    }
656
0
    ibuf.alloc(ph.c_len);
657
0
    fi->readx(ibuf, ph.c_len);
658
0
    obuf.allocForDecompression(ph.u_len);
659
0
    decompress(ibuf, obuf);
660
661
0
    Filter ft(ph.level);
662
0
    ft.init(ph.filter, 0);
663
0
    ft.cto = (unsigned char) ph.filter_cto;
664
0
    ft.unfilter(obuf, ph.u_len);
665
0
    fo->write(obuf, ph.u_len);
666
0
    obuf.dealloc();
667
0
    ibuf.dealloc();
668
669
0
    fi->seek(p_note1->sh_offset, SEEK_SET);
670
0
    fi->readx(&word, sizeof(word));
671
0
    ph.u_len = word;
672
0
    ph.c_len = p_note1->sh_size - sizeof(word);
673
0
    ibuf.alloc(ph.c_len);
674
0
    fi->readx(ibuf, p_note1->sh_size - sizeof(ph.u_len));
675
0
    obuf.allocForDecompression(ph.u_len);
676
0
    decompress(ibuf, obuf, false);
677
0
    fo->write(obuf, ph.u_len);
678
0
    obuf.dealloc();
679
0
    ibuf.dealloc();
680
681
0
    ph = ph_tmp;
682
0
}
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> >::unpack(OutputFile*)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> >::unpack(OutputFile*)
Unexecuted instantiation: PackVmlinuxBase<N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> >::unpack(OutputFile*)
683
684
685
/*************************************************************************
686
//
687
**************************************************************************/
688
689
const int *PackVmlinuxI386::getCompressionMethods(int method, int level) const
690
0
{
691
0
    return Packer::getDefaultCompressionMethods_le32(method, level);
692
0
}
693
694
695
const int *PackVmlinuxI386::getFilters() const
696
0
{
697
0
    static const int filters[] = {
698
0
        0x49, 0x46,
699
0
    FT_END };
700
0
    return filters;
701
0
}
702
703
const int *PackVmlinuxARMEL::getCompressionMethods(int method, int level) const
704
0
{
705
0
    return Packer::getDefaultCompressionMethods_8(method, level);
706
0
}
707
708
const int *PackVmlinuxARMEB::getCompressionMethods(int method, int level) const
709
0
{
710
0
    return Packer::getDefaultCompressionMethods_8(method, level);
711
0
}
712
713
const int *PackVmlinuxPPC32::getCompressionMethods(int method, int level) const
714
0
{
715
    // No real dependency on LE32.
716
0
    return Packer::getDefaultCompressionMethods_le32(method, level);
717
0
}
718
719
const int *PackVmlinuxPPC64LE::getCompressionMethods(int method, int level) const
720
0
{
721
    // No real dependency on LE32.
722
0
    return Packer::getDefaultCompressionMethods_le32(method, level);
723
0
}
724
725
726
const int *PackVmlinuxARMEL::getFilters() const
727
0
{
728
0
    static const int f50[] = { 0x50, FT_END };
729
0
    return f50;
730
0
}
731
732
const int *PackVmlinuxARMEB::getFilters() const
733
0
{
734
0
    static const int f51[] = { 0x51, FT_END };
735
0
    return f51;
736
0
}
737
738
const int *PackVmlinuxPPC32::getFilters() const
739
0
{
740
0
    static const int fd0[] = { 0xd0, FT_END };
741
0
    return fd0;
742
0
}
743
744
const int *PackVmlinuxPPC64LE::getFilters() const
745
0
{
746
0
    static const int fd0[] = { 0xd0, FT_END };
747
0
    return fd0;
748
0
}
749
750
//
751
// Examples as of 2004-07-16 [readelf --segments vmlinux  # before fiddling]:
752
//
753
//----- kernel-2.6.7 plain [defconfig?]
754
//Program Headers(2):
755
//  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
756
//  LOAD           0x001000 0x00100000 0x00100000 0x1c7e61 0x1c7e61 R E 0x1000
757
//  LOAD           0x1c8e64 0x002c8e64 0x002c8e64 0x00000 0x00000 RW  0x1000
758
//
759
//----- kernel-2.6.7-1.488 Fedora Core 3 test 1
760
//Program Headers(5):
761
//  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
762
//  LOAD           0x001000 0x02100000 0x02100000 0x202246 0x202246 R E 0x1000
763
//  LOAD           0x204000 0xffff3000 0x02303000 0x00664 0x00664 R E 0x1000
764
//  LOAD           0x205000 0x02304000 0x02304000 0x43562 0x43562 R   0x1000
765
//  LOAD           0x249000 0x02348000 0x02348000 0x81800 0xcb0fc RWE 0x1000
766
//  STACK          0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
767
//
768
//----- kernel-2.6.18-1.2778 Fedora Core 6 test 3
769
//Program Headers(3)
770
//  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
771
//  LOAD           0x001000 0xc0400000 0x00400000 0x279820 0x279820 R E 0x1000
772
//  LOAD           0x27b000 0xc067a000 0x0067a000 0x10ee64 0x1b07e8 RWE 0x1000
773
//  NOTE           0x000000 0x00000000 0x00000000 0x00000 0x00000 R   0x4
774
775
bool PackVmlinuxI386::is_valid_e_entry(Addr e_entry)
776
0
{
777
0
    return 0==(0x000fffff & e_entry); // entry on whole 1 MiB
778
0
}
779
780
781
Linker* PackVmlinuxI386::newLinker() const
782
0
{
783
0
    return new ElfLinkerX86;
784
0
}
785
786
787
void PackVmlinuxI386::buildLoader(const Filter *ft)
788
0
{
789
    // prepare loader
790
0
    initLoader(stub_i386_linux_kernel_vmlinux, sizeof(stub_i386_linux_kernel_vmlinux));
791
0
    addLoader("LINUX000",
792
0
              (0x40==(0xf0 & ft->id)) ? "LXCKLLT1" : (ft->id ? "LXCALLT1" : ""),
793
0
              "LXMOVEUP",
794
0
              getDecompressorSections(),
795
0
              nullptr
796
0
             );
797
0
    if (ft->id) {
798
0
        assert(ft->calls > 0);
799
0
        if (0x40==(0xf0 & ft->id)) {
800
0
            addLoader("LXCKLLT9", nullptr);
801
0
        }
802
0
        else {
803
0
            addLoader("LXCALLT9", nullptr);
804
0
        }
805
0
        addFilter32(ft->id);
806
0
    }
807
0
    addLoader("LINUX990",
808
0
              ((ph.first_offset_found == 1) ? "LINUX991" : ""),
809
0
              "LINUX992,IDENTSTR,UPX1HEAD", nullptr);
810
0
}
811
812
void PackVmlinuxAMD64::buildLoader(const Filter *ft)
813
0
{
814
    // prepare loader
815
0
    initLoader(stub_amd64_linux_kernel_vmlinux, sizeof(stub_amd64_linux_kernel_vmlinux));
816
0
    addLoader("LINUX000",
817
0
              (0x40==(0xf0 & ft->id)) ? "LXCKLLT1" : (ft->id ? "LXCALLT1" : ""),
818
0
              "LXMOVEUP",
819
0
              getDecompressorSections(),
820
0
              nullptr
821
0
             );
822
0
    if (ft->id) {
823
0
        assert(ft->calls > 0);
824
0
        if (0x40==(0xf0 & ft->id)) {
825
0
            addLoader("LXCKLLT9", nullptr);
826
0
        }
827
0
        else {
828
0
            addLoader("LXCALLT9", nullptr);
829
0
        }
830
0
        addFilter32(ft->id);
831
0
    }
832
0
    addLoader("LINUX990",
833
0
              ((ph.first_offset_found == 1) ? "LINUX991" : ""),
834
0
              "LINUX992,IDENTSTR,UPX1HEAD", nullptr);
835
0
}
836
837
bool PackVmlinuxARMEL::is_valid_e_entry(Addr e_entry)
838
0
{
839
0
    return 0xc0008000==e_entry;
840
0
}
841
842
bool PackVmlinuxARMEB::is_valid_e_entry(Addr e_entry)
843
0
{
844
0
    return 0xc0008000==e_entry;
845
0
}
846
847
bool PackVmlinuxPPC32::is_valid_e_entry(Addr e_entry)
848
0
{
849
0
    return 0xc0000000==e_entry;
850
0
}
851
852
bool PackVmlinuxPPC64LE::is_valid_e_entry(Addr e_entry)
853
0
{
854
0
    return 0xc0000000==e_entry;
855
0
}
856
857
Linker* PackVmlinuxARMEL::newLinker() const
858
0
{
859
0
    return new ElfLinkerArmLE;
860
0
}
861
862
Linker* PackVmlinuxARMEB::newLinker() const
863
0
{
864
0
    return new ElfLinkerArmBE;
865
0
}
866
867
Linker* PackVmlinuxPPC32::newLinker() const
868
0
{
869
0
    return new ElfLinkerPpc32;
870
0
}
871
872
Linker* PackVmlinuxPPC64LE::newLinker() const
873
0
{
874
0
    return new ElfLinkerPpc64le;
875
0
}
876
877
878
void PackVmlinuxARMEL::buildLoader(const Filter *ft)
879
0
{
880
    // prepare loader
881
0
    initLoader(stub_arm_v5a_linux_kernel_vmlinux, sizeof(stub_arm_v5a_linux_kernel_vmlinux));
882
0
    addLoader("LINUX000", nullptr);
883
0
    if (ft->id) {
884
0
        assert(ft->calls > 0);
885
0
        addLoader("LINUX010", nullptr);
886
0
    }
887
0
    addLoader("LINUX020", nullptr);
888
0
    if (ft->id) {
889
0
        addFilter32(ft->id);
890
0
    }
891
0
    addLoader("LINUX030", nullptr);
892
0
         if (ph.method == M_NRV2E_8) addLoader("NRV2E", nullptr);
893
0
    else if (ph.method == M_NRV2B_8) addLoader("NRV2B", nullptr);
894
0
    else if (ph.method == M_NRV2D_8) addLoader("NRV2D", nullptr);
895
0
    else if (M_IS_LZMA(ph.method))   addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr);
896
0
    else throwBadLoader();
897
0
    addLoader("IDENTSTR,UPX1HEAD", nullptr);
898
0
}
899
900
void PackVmlinuxARMEB::buildLoader(const Filter *ft)
901
0
{
902
    // prepare loader
903
0
    initLoader(stub_armeb_v5a_linux_kernel_vmlinux, sizeof(stub_armeb_v5a_linux_kernel_vmlinux));
904
0
    addLoader("LINUX000", nullptr);
905
0
    if (ft->id) {
906
0
        assert(ft->calls > 0);
907
0
        addLoader("LINUX010", nullptr);
908
0
    }
909
0
    addLoader("LINUX020", nullptr);
910
0
    if (ft->id) {
911
0
        addFilter32(ft->id);
912
0
    }
913
0
    addLoader("LINUX030", nullptr);
914
0
         if (ph.method == M_NRV2E_8) addLoader("NRV2E", nullptr);
915
0
    else if (ph.method == M_NRV2B_8) addLoader("NRV2B", nullptr);
916
0
    else if (ph.method == M_NRV2D_8) addLoader("NRV2D", nullptr);
917
0
    else if (M_IS_LZMA(ph.method))   addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr);
918
0
    else throwBadLoader();
919
0
    addLoader("IDENTSTR,UPX1HEAD", nullptr);
920
0
}
921
922
void PackVmlinuxPPC32::buildLoader(const Filter *ft)
923
0
{
924
    // prepare loader
925
0
    initLoader(stub_powerpc_linux_kernel_vmlinux, sizeof(stub_powerpc_linux_kernel_vmlinux));
926
0
    addLoader("LINUX000", nullptr);
927
0
    if (ft->id) {
928
0
        assert(ft->calls > 0);
929
0
        addLoader("LINUX010", nullptr);
930
0
    }
931
0
    addLoader("LINUX020", nullptr);
932
0
    if (ft->id) {
933
0
        addFilter32(ft->id);
934
0
    }
935
0
    addLoader("LINUX030", nullptr);
936
0
         if (ph.method == M_NRV2E_LE32) addLoader("NRV2E,NRV_TAIL", nullptr);
937
0
    else if (ph.method == M_NRV2B_LE32) addLoader("NRV2B,NRV_TAIL", nullptr);
938
0
    else if (ph.method == M_NRV2D_LE32) addLoader("NRV2D,NRV_TAIL", nullptr);
939
0
    else if (M_IS_LZMA(ph.method))   addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr);
940
0
    else throwBadLoader();
941
0
    if (hasLoaderSection("CFLUSH"))
942
0
        addLoader("CFLUSH");
943
944
0
    addLoader("IDENTSTR,UPX1HEAD", nullptr);
945
0
}
946
947
static const CLANG_FORMAT_DUMMY_STATEMENT
948
#include "stub/powerpc64le-linux.kernel.vmlinux.h"
949
void PackVmlinuxPPC64LE::buildLoader(const Filter *ft)
950
0
{
951
    // prepare loader
952
0
    initLoader(stub_powerpc64le_linux_kernel_vmlinux, sizeof(stub_powerpc64le_linux_kernel_vmlinux));
953
0
    addLoader("LINUX000", nullptr);
954
0
    if (ft->id) {
955
0
        assert(ft->calls > 0);
956
0
        addLoader("LINUX010", nullptr);
957
0
    }
958
0
    addLoader("LINUX020", nullptr);
959
0
    if (ft->id) {
960
0
        addFilter32(ft->id);
961
0
    }
962
0
    addLoader("LINUX030", nullptr);
963
0
         if (ph.method == M_NRV2E_LE32) addLoader("NRV2E,NRV_TAIL", nullptr);
964
0
    else if (ph.method == M_NRV2B_LE32) addLoader("NRV2B,NRV_TAIL", nullptr);
965
0
    else if (ph.method == M_NRV2D_LE32) addLoader("NRV2D,NRV_TAIL", nullptr);
966
0
    else if (M_IS_LZMA(ph.method))   addLoader("LZMA_ELF00,LZMA_DEC10,LZMA_DEC30", nullptr);
967
0
    else throwBadLoader();
968
0
    if (hasLoaderSection("CFLUSH"))
969
0
        addLoader("CFLUSH");
970
971
0
    addLoader("IDENTSTR,UPX1HEAD", nullptr);
972
0
}
973
974
975
static const CLANG_FORMAT_DUMMY_STATEMENT
976
#include "stub/i386-linux.kernel.vmlinux-head.h"
977
static const CLANG_FORMAT_DUMMY_STATEMENT
978
#include "stub/amd64-linux.kernel.vmlinux-head.h"
979
static const CLANG_FORMAT_DUMMY_STATEMENT
980
#include "stub/arm.v5a-linux.kernel.vmlinux-head.h"
981
static const CLANG_FORMAT_DUMMY_STATEMENT
982
#include "stub/armeb.v5a-linux.kernel.vmlinux-head.h"
983
static const CLANG_FORMAT_DUMMY_STATEMENT
984
#include "stub/powerpc-linux.kernel.vmlinux-head.h"
985
986
unsigned PackVmlinuxI386::write_vmlinux_head(
987
    OutputFile *fo,
988
    Shdr *stxt
989
)
990
0
{
991
    // COMPRESSED_LENGTH
992
0
    fo->write(&stub_i386_linux_kernel_vmlinux_head[0],
993
0
        sizeof(stub_i386_linux_kernel_vmlinux_head)-(1+ 4) +1);
994
0
    TE32 tmp_u32; tmp_u32 = ph.c_len; fo->write(&tmp_u32, 4);
995
996
0
    stxt->sh_size += sizeof(stub_i386_linux_kernel_vmlinux_head);
997
998
0
    return sizeof(stub_i386_linux_kernel_vmlinux_head);
999
0
}
1000
1001
unsigned PackVmlinuxAMD64::write_vmlinux_head(
1002
    OutputFile *fo,
1003
    Shdr *stxt
1004
)
1005
0
{
1006
    // COMPRESSED_LENGTH
1007
0
    fo->write(&stub_amd64_linux_kernel_vmlinux_head[0],
1008
0
        sizeof(stub_amd64_linux_kernel_vmlinux_head)-(1+ 4) +1);
1009
0
    TE32 tmp_u32; tmp_u32 = ph.c_len; fo->write(&tmp_u32, 4);
1010
0
printf("  Compressed length=0x%x\n", ph.c_len);
1011
0
printf("UnCompressed length=0x%x\n", ph.u_len);
1012
1013
0
    stxt->sh_size += sizeof(stub_amd64_linux_kernel_vmlinux_head);
1014
1015
0
    return sizeof(stub_amd64_linux_kernel_vmlinux_head);
1016
0
}
1017
1018
void PackVmlinuxARMEL::defineDecompressorSymbols()
1019
0
{
1020
0
    super::defineDecompressorSymbols();
1021
0
    linker->defineSymbol(  "COMPRESSED_LENGTH", ph.c_len);
1022
0
    linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len);
1023
0
    linker->defineSymbol("METHOD", ph.method);
1024
0
}
1025
1026
void PackVmlinuxARMEB::defineDecompressorSymbols()
1027
0
{
1028
0
    super::defineDecompressorSymbols();
1029
0
    linker->defineSymbol(  "COMPRESSED_LENGTH", ph.c_len);
1030
0
    linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len);
1031
0
    linker->defineSymbol("METHOD", ph.method);
1032
0
}
1033
1034
void PackVmlinuxPPC32::defineDecompressorSymbols()
1035
0
{
1036
0
    super::defineDecompressorSymbols();
1037
    // linker->defineSymbol(  "COMPRESSED_LENGTH", ph.c_len);
1038
    // linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len);
1039
    // linker->defineSymbol("METHOD", ph.method);
1040
0
}
1041
1042
void PackVmlinuxPPC64LE::defineDecompressorSymbols()
1043
0
{
1044
0
    super::defineDecompressorSymbols();
1045
    // linker->defineSymbol(  "COMPRESSED_LENGTH", ph.c_len);
1046
    // linker->defineSymbol("UNCOMPRESSED_LENGTH", ph.u_len);
1047
    // linker->defineSymbol("METHOD", ph.method);
1048
0
}
1049
1050
void PackVmlinuxI386::defineDecompressorSymbols()
1051
0
{
1052
0
    super::defineDecompressorSymbols();
1053
0
    linker->defineSymbol("ENTRY_POINT", phdri[0].p_paddr);
1054
0
    linker->defineSymbol("PHYSICAL_START", phdri[0].p_paddr);
1055
0
}
1056
1057
void PackVmlinuxAMD64::defineDecompressorSymbols()
1058
0
{
1059
0
    super::defineDecompressorSymbols();
1060
    // We assume a 32-bit boot loader, so we use the 32-bit convention
1061
    // of "enter at the beginning" (startup_32).  The 64-bit convention
1062
    // would be to use ehdri.e_entry (startup_64).
1063
0
    linker->defineSymbol("ENTRY_POINT", (unsigned) phdri[0].p_paddr);
1064
0
    linker->defineSymbol("PHYSICAL_START", (unsigned) phdri[0].p_paddr);
1065
0
}
1066
1067
unsigned PackVmlinuxARMEL::write_vmlinux_head(
1068
    OutputFile *fo,
1069
    Shdr *stxt
1070
)
1071
0
{
1072
    // First word from vmlinux-head.S
1073
0
    fo->write(&stub_arm_v5a_linux_kernel_vmlinux_head[0], 4);
1074
1075
    // Second word
1076
0
    TE32 tmp_u32;
1077
0
    unsigned const t = (0xff000000 &
1078
0
            BeLePolicy::get32(&stub_arm_v5a_linux_kernel_vmlinux_head[4]))
1079
0
        | (0x00ffffff & (0u - 1 + ((3+ ph.c_len)>>2)));
1080
0
    tmp_u32 = t;
1081
0
    fo->write(&tmp_u32, 4);
1082
1083
0
    stxt->sh_addralign = 4;
1084
0
    stxt->sh_size += sizeof(stub_arm_v5a_linux_kernel_vmlinux_head);
1085
1086
0
    return sizeof(stub_arm_v5a_linux_kernel_vmlinux_head);
1087
0
}
1088
1089
unsigned PackVmlinuxARMEB::write_vmlinux_head(
1090
    OutputFile *fo,
1091
    Shdr *stxt
1092
)
1093
0
{
1094
    // First word from vmlinux-head.S
1095
0
    fo->write(&stub_armeb_v5a_linux_kernel_vmlinux_head[0], 4);
1096
1097
    // Second word
1098
0
    TE32 tmp_u32;
1099
0
    unsigned const t = (0xff000000 &
1100
0
            BeLePolicy::get32(&stub_armeb_v5a_linux_kernel_vmlinux_head[4]))
1101
0
        | (0x00ffffff & (0u - 1 + ((3+ ph.c_len)>>2)));
1102
0
    tmp_u32 = t;
1103
0
    fo->write(&tmp_u32, 4);
1104
1105
0
    stxt->sh_addralign = 4;
1106
0
    stxt->sh_size += sizeof(stub_armeb_v5a_linux_kernel_vmlinux_head);
1107
1108
0
    return sizeof(stub_armeb_v5a_linux_kernel_vmlinux_head);
1109
0
}
1110
1111
unsigned PackVmlinuxPPC32::write_vmlinux_head(
1112
    OutputFile * /*fo*/,
1113
    Shdr * /*stxt*/
1114
)
1115
0
{
1116
0
    return 0;
1117
0
}
1118
1119
unsigned PackVmlinuxPPC64LE::write_vmlinux_head(
1120
    OutputFile * /*const fo*/,
1121
    Shdr * /*const stxt*/
1122
)
1123
0
{
1124
0
    return 0;
1125
0
}
1126
1127
1128
bool PackVmlinuxARMEL::has_valid_vmlinux_head()
1129
0
{
1130
0
    TE32 buf[2];
1131
0
    fi->seek(p_text->sh_offset + sizeof(stub_arm_v5a_linux_kernel_vmlinux_head) -8, SEEK_SET);
1132
0
    fi->readx(buf, sizeof(buf));
1133
    //unsigned const word0 = buf[0];
1134
0
    unsigned const word1 = buf[1];
1135
0
    if (0xeb==(word1>>24)
1136
0
    &&  (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) {
1137
0
        return true;
1138
0
    }
1139
0
    return false;
1140
0
}
1141
1142
bool PackVmlinuxARMEB::has_valid_vmlinux_head()
1143
0
{
1144
0
    TE32 buf[2];
1145
0
    fi->seek(p_text->sh_offset + sizeof(stub_armeb_v5a_linux_kernel_vmlinux_head) -8, SEEK_SET);
1146
0
    fi->readx(buf, sizeof(buf));
1147
    //unsigned const word0 = buf[0];
1148
0
    unsigned const word1 = buf[1];
1149
0
    if (0xeb==(word1>>24)
1150
0
    &&  (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) {
1151
0
        return true;
1152
0
    }
1153
0
    return false;
1154
0
}
1155
1156
bool PackVmlinuxPPC32::has_valid_vmlinux_head()
1157
0
{
1158
0
    TE32 buf[2];
1159
0
    fi->seek(p_text->sh_offset + sizeof(stub_powerpc_linux_kernel_vmlinux_head) -8, SEEK_SET);
1160
0
    fi->readx(buf, sizeof(buf));
1161
    //unsigned const word0 = buf[0];
1162
0
    unsigned const word1 = buf[1];
1163
0
    if (0xeb==(word1>>24)
1164
0
    &&  (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) {
1165
0
        return true;
1166
0
    }
1167
0
    return false;
1168
0
}
1169
1170
static const CLANG_FORMAT_DUMMY_STATEMENT
1171
#include "stub/powerpc64le-linux.kernel.vmlinux-head.h"
1172
bool PackVmlinuxPPC64LE::has_valid_vmlinux_head()
1173
0
{
1174
0
    TE64 buf[2];
1175
0
    fi->seek(p_text->sh_offset + sizeof(stub_powerpc64le_linux_kernel_vmlinux_head) -8, SEEK_SET);
1176
0
    fi->readx(buf, sizeof(buf));
1177
    //unsigned const word0 = buf[0];
1178
0
    unsigned const word1 = buf[1];
1179
0
    if (0xeb==(word1>>24)
1180
0
    &&  (0x00ffffff& word1)==(0u - 1 + ((3+ ph.c_len)>>2))) {
1181
0
        return true;
1182
0
    }
1183
0
    return false;
1184
0
}
1185
1186
bool PackVmlinuxI386::has_valid_vmlinux_head()
1187
0
{
1188
0
    unsigned char buf[5];
1189
0
    fi->seek(p_text->sh_offset + sizeof(stub_i386_linux_kernel_vmlinux_head) -5, SEEK_SET);
1190
0
    fi->readx(&buf[0], 5);
1191
0
    if (0xE8!=buf[0] ||  BeLePolicy::get32(&buf[1]) != ph.c_len)
1192
0
    {
1193
0
        return false;
1194
0
    }
1195
0
    return true;
1196
0
}
1197
1198
bool PackVmlinuxAMD64::has_valid_vmlinux_head()
1199
0
{
1200
0
    unsigned char buf[5];
1201
0
    fi->seek(p_text->sh_offset + sizeof(stub_amd64_linux_kernel_vmlinux_head) -5, SEEK_SET);
1202
0
    fi->readx(&buf[0], 5);
1203
0
    if (0xE8!=buf[0] ||  BeLePolicy::get32(&buf[1]) != ph.c_len)
1204
0
    {
1205
0
        return false;
1206
0
    }
1207
0
    return true;
1208
0
}
1209
1210
1211
/*************************************************************************
1212
//
1213
**************************************************************************/
1214
1215
const int *PackVmlinuxAMD64::getCompressionMethods(int method, int level) const
1216
0
{
1217
0
    return Packer::getDefaultCompressionMethods_le32(method, level);
1218
0
}
1219
1220
1221
const int *PackVmlinuxAMD64::getFilters() const
1222
0
{
1223
0
    static const int filters[] = {
1224
0
        0x49, 0x46,
1225
0
    -1 };
1226
0
    return filters;
1227
0
}
1228
1229
bool PackVmlinuxAMD64::is_valid_e_entry(Addr e_entry)
1230
0
{
1231
0
    return 0x200000<=e_entry; // 2 MiB
1232
0
}
1233
1234
Linker* PackVmlinuxAMD64::newLinker() const
1235
0
{
1236
0
    return new ElfLinkerX86;
1237
0
}
1238
1239
1240
1241
// instantiate instances
1242
template class PackVmlinuxBase<ElfClass_BE32>;
1243
// template class PackVmlinuxBase<ElfClass_BE64>; // currently not used
1244
template class PackVmlinuxBase<ElfClass_LE32>;
1245
template class PackVmlinuxBase<ElfClass_LE64>;
1246
1247
/* vim:set ts=4 sw=4 et: */