summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/beam_file.h
blob: 7168ffc793c029a7b2180ed9177dec96afb9f5fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2020-2023. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * %CopyrightEnd%
 */

#ifndef _BEAM_FILE_H
#define _BEAM_FILE_H

#define ERTS_BEAM_MAX_OPARGS 8

#include "sys.h"
#include "atom.h"
#include "beam_types.h"

#define CHECKSUM_SIZE 16

#define MakeIffId(a, b, c, d) \
  (((Uint) (a) << 24) | ((Uint) (b) << 16) | ((Uint) (c) << 8) | (Uint) (d))

typedef struct {
    Sint32 form_id;

    Sint32 size;
    const byte *data;
} IFF_File;

typedef struct {
    Uint32 iff_id;

    Sint32 size;
    const byte *data;
} IFF_Chunk;

int iff_init(const byte *data, size_t size, IFF_File *iff);

/** @brief Reads a specific chunk from the given IFF file, skipping all
 * validation.
 *
 * @return 1 on success, 0 on failure */
int iff_read_chunk(IFF_File *iff, Uint id, IFF_Chunk *chunk);

typedef struct {
    Sint32 count;
    Eterm *entries;
} BeamFile_AtomTable;

typedef struct {
    Sint32 function_count;
    Sint32 label_count;
    Sint32 max_opcode;

    const byte *data;
    Sint32 size;
} BeamFile_Code;

typedef struct {
    Eterm function;
    int arity;

    /* Entry point */
    Sint32 label;
} BeamFile_ExportEntry;

typedef struct {
    Sint32 count;
    BeamFile_ExportEntry *entries;
} BeamFile_ExportTable;

typedef struct {
    Eterm module;
    Eterm function;
    int arity;
} BeamFile_ImportEntry;

typedef struct {
    Sint32 count;
    BeamFile_ImportEntry *entries;
} BeamFile_ImportTable;

typedef struct {
    Sint32 index;
    Sint32 old_uniq;

    Eterm function;
    Sint32 num_free;
    Sint32 arity;
    Sint32 label;
} BeamFile_LambdaEntry;

typedef struct {
    Sint count;
    BeamFile_LambdaEntry *entries;
} BeamFile_LambdaTable;

typedef struct {
    Sint32 location;
    Sint32 name_index;
} BeamFile_LineEntry;

typedef struct {
    Sint32 instruction_count;
    Sint32 flags;

    Sint32 name_count;
    Sint *names;

    Sint32 location_size;
    Sint32 item_count;
    BeamFile_LineEntry *items;
} BeamFile_LineTable;

typedef struct {
    struct erl_heap_fragment *heap_fragments;
    Eterm value;
} BeamFile_LiteralEntry;

typedef struct {
    Sint heap_size;

    Sint32 allocated;
    Sint32 count;
    BeamFile_LiteralEntry *entries;
} BeamFile_LiteralTable;

typedef struct {
    /* To simplify code that queries types, the first entry (which must be
     * present) is always the "any type." */
    Sint32 count;
    char fallback; /* If this is a fallback type table */
    BeamType *entries;
} BeamFile_TypeTable;

typedef struct {
    IFF_File iff;

    Eterm module;

    byte checksum[CHECKSUM_SIZE];

    BeamFile_AtomTable atoms;
    BeamFile_ImportTable imports;
    BeamFile_ExportTable exports;
#ifdef BEAMASM
    BeamFile_ExportTable locals;
#endif
    BeamFile_LambdaTable lambdas;
    BeamFile_LineTable lines;
    BeamFile_TypeTable types;

    /* Static literals are those defined in the file, and dynamic literals are
     * those created when loading. The former is positively indexed starting
     * from 0, while the latter is negatively indexed starting at -1.
     *
     * These are kept separate to enhance validation, erroring out if any TAG_q
     * read from the file refers to a literal outside the static table. */
    BeamFile_LiteralTable static_literals;
    BeamFile_LiteralTable dynamic_literals;

    BeamFile_Code code;

    /* Data-only chunks */
    struct {
        const byte *data;
        Sint32 size;
    } attributes, compile_info, strings;
} BeamFile;

enum beamfile_read_result {
    BEAMFILE_READ_SUCCESS,

    BEAMFILE_READ_CORRUPT_FILE_HEADER,

    /* Mandatory chunks */
    BEAMFILE_READ_MISSING_ATOM_TABLE,
    BEAMFILE_READ_OBSOLETE_ATOM_TABLE,
    BEAMFILE_READ_CORRUPT_ATOM_TABLE,
    BEAMFILE_READ_MISSING_CODE_CHUNK,
    BEAMFILE_READ_CORRUPT_CODE_CHUNK,
    BEAMFILE_READ_MISSING_EXPORT_TABLE,
    BEAMFILE_READ_CORRUPT_EXPORT_TABLE,
    BEAMFILE_READ_MISSING_IMPORT_TABLE,
    BEAMFILE_READ_CORRUPT_IMPORT_TABLE,
    BEAMFILE_READ_CORRUPT_LOCALS_TABLE,

    /* Optional chunks */
    BEAMFILE_READ_CORRUPT_LAMBDA_TABLE,
    BEAMFILE_READ_CORRUPT_LINE_TABLE,
    BEAMFILE_READ_CORRUPT_LITERAL_TABLE,
    BEAMFILE_READ_CORRUPT_TYPE_TABLE
};

typedef struct {
    /* TAG_xyz */
    UWord type;
    UWord val;
} BeamOpArg;

typedef struct beamop {
    /* Opcode */
    int op;

    /* Number of arguments */
    int arity;

    /* Default buffer for arguments */
    BeamOpArg def_args[ERTS_BEAM_MAX_OPARGS];

    /* Actual arguments */
    BeamOpArg *a;

    struct beamop *next;
} BeamOp;

typedef struct beamop_block {
    BeamOp ops[32];
    struct beamop_block* next;
} BeamOpBlock;

typedef struct {
    BeamOpBlock *beamop_blocks;
    BeamOp *free;
} BeamOpAllocator;

/*
 * !! These are included here to break a circular dependency !!
 */
#include "erl_process.h"
#include "erl_message.h"

void beamfile_init(void);

/** @brief Reads the given module binary into \p beam and validates its
 * structural integrity. */
enum beamfile_read_result
beamfile_read(const byte *data, size_t size, BeamFile *beam);

/** @brief Releases all resources associated with \p beam, but does not free
 * it. */
void beamfile_free(BeamFile *beam);

/** @brief Copies a term into the dynamic literal table
 *
 * @param[in] deduplicate Whether to try to deduplicate the term before
 * insertion. Set to zero if you require a new unique literal, for example if
 * it needs to be modified in the late stages of loading.
 *
 * @return A literal index that can be used in beamfile_get_literal */
Sint beamfile_add_literal(BeamFile *beam, Eterm term, int deduplicate);

/** @brief Gets a term from the literal table.
 *
 * The returned term is valid until the BeamFile is freed or the literals are
 * moved through \c beamfile_move_literals , which is destructive and makes
 * all previously returned terms invalid.
 *
 * As such, the return value should only be used briefly in pattern matching or
 * similar until they're permanently moved to the literal area. */
Eterm beamfile_get_literal(const BeamFile *beam, Sint index);

/** @brief Destructively moves all literals to hpp/oh.
 *
 * It's safe to use \c beamfile_get_literal both before and after this call,
 * but previously retrieved terms will be destroyed and need to be retrieved
 * again. */
void beamfile_move_literals(BeamFile *beam, Eterm **hpp, ErlOffHeap *oh);

void beamopallocator_init(BeamOpAllocator *allocator);
void beamopallocator_dtor(BeamOpAllocator *allocator);

ERTS_GLB_INLINE
BeamOp *beamopallocator_new_op(BeamOpAllocator *allocator);

ERTS_GLB_INLINE
void beamopallocator_free_op(BeamOpAllocator *allocator, BeamOp *op);

/** @brief Internal helper for \c beamopallocator_new_op */
void beamopallocator_expand__(BeamOpAllocator *allocator);

/**/

typedef struct BeamCodeReader__ BeamCodeReader;

BeamCodeReader *beamfile_get_code(BeamFile *beam, BeamOpAllocator *op_alloc);
int beamcodereader_next(BeamCodeReader *code_reader, BeamOp **op);
void beamcodereader_close(BeamCodeReader *code_reader);

/**/

#if ERTS_GLB_INLINE_INCL_FUNC_DEF

#ifdef DEBUG
# define GARBAGE__ 0xCC
# define DEBUG_INIT_BEAMOP(Dst) sys_memset(Dst, GARBAGE__, sizeof(BeamOp))
#else
# define DEBUG_INIT_BEAMOP(Dst)
#endif

ERTS_GLB_INLINE
BeamOp *beamopallocator_new_op(BeamOpAllocator *allocator) {
    BeamOp *res;

    if (allocator->free == NULL) {
        beamopallocator_expand__(allocator);
    }

    res = allocator->free;
    allocator->free = res->next;

    DEBUG_INIT_BEAMOP(res);
    res->a = res->def_args;

    return res;
}

ERTS_GLB_INLINE
void beamopallocator_free_op(BeamOpAllocator *allocator, BeamOp *op) {
    if (op->a != op->def_args) {
        erts_free(ERTS_ALC_T_LOADER_TMP, op->a);
    }

    op->next = allocator->free;
    allocator->free = op;
}

#endif

#endif