Coverage Report

Created: 2026-06-30 07:09

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