-
Notifications
You must be signed in to change notification settings - Fork 1
/
common.c
139 lines (121 loc) · 3.58 KB
/
common.c
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
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include "common.h"
// The global trace flag
int g_trace = 0;
#define MORE(b) (((b) & 0x80) != 0)
#define ERROR (len != NULL ? *len = -(ptr - start) : 0), 0
#define BODY(type, mask, legal) \
const uint8_t* start = ptr; \
type result = 0, shift = 0; \
while (ptr < limit) { \
uint8_t b = *ptr; \
ptr++; \
result = result | (((type)b & 0x7F) << shift); \
shift += 7; \
if (shift > (8*sizeof(type))) { \
if (MORE(b) != 0) return ERROR; /* overlong */ \
uint8_t upper = b & mask; \
if (upper != 0 && upper != legal) return ERROR; /* out of range */ \
if (len != NULL) *len = (ptr - start); \
return result; \
} \
if (MORE(b)) continue; \
type rem = ((8*sizeof(type)) - shift); \
if (len != NULL) *len = (ptr - start); \
return ((0x7F & mask) == legal) ? (result << rem) >> rem : result; \
} \
return ERROR;
int32_t decode_i32leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) {
BODY(int32_t, 0xF8, 0x78);
}
uint32_t decode_u32leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) {
BODY(uint32_t, 0xF8, 0x08);
}
int64_t decode_i64leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) {
BODY(int64_t, 0xFF, 0x7F);
}
uint64_t decode_u64leb(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) {
BODY(int64_t, 0xFF, 0x01);
}
uint32_t decode_u32(const uint8_t* ptr, const uint8_t* limit, ssize_t *len) {
ssize_t remain = limit - ptr;
if (remain < 4) {
if (remain > 0) *len = -remain;
else *len = remain;
return 0;
}
uint32_t b0 = ptr[0];
uint32_t b1 = ptr[1];
uint32_t b2 = ptr[2];
uint32_t b3 = ptr[3];
*len = 4;
return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
}
ssize_t load_file(const char* path, uint8_t** start, uint8_t** end) {
// Open the file for reading.
int fd = open(path, O_RDONLY);
if (fd < 0) return fd;
// Query the size of the file in bytes.
struct stat statbuf;
int r = fstat(fd, &statbuf);
if (r < 0) { // stat call failed.
close(fd);
return r;
}
// Reject overly large files.
off_t size = statbuf.st_size;
if (size > MAX_FILE_SIZE) { // too large.
close(fd);
return -1;
}
// Allocate memory to store the bytes.
*start = (uint8_t*)malloc(size);
*end = *start + size;
off_t remain = size;
// Read the bytes from the file until done.
for (uint8_t* p = *start; remain > 0; ) {
r = read(fd, p, remain);
if (r < 0) { // reading failed.
close(fd);
return -2;
}
remain -= r;
p += r;
}
return (int)size;
}
// Read an unsigned 32-bit LEB, advancing the buffer.
uint32_t read_u32leb(buffer_t* buf) {
ssize_t leblen = 0;
if (buf->ptr >= buf->end) return 0;
uint32_t val = decode_u32leb(buf->ptr, buf->end, &leblen);
if (leblen <= 0) buf->ptr = buf->end; // force failure
else buf->ptr += leblen;
return val;
}
// Read a signed 32-bit LEB, advancing the buffer.
int32_t read_i32leb(buffer_t* buf) {
ssize_t leblen = 0;
if (buf->ptr >= buf->end) return 0;
int32_t val = decode_i32leb(buf->ptr, buf->end, &leblen);
if (leblen <= 0) buf->ptr = buf->end; // force failure
else buf->ptr += leblen;
return val;
}
// Read an unsigned 8-bit byte, advancing the buffer.
uint32_t read_u8(buffer_t* buf) {
if (buf->ptr >= buf->end) return 0;
byte val = *buf->ptr;
buf->ptr++;
return val;
}
ssize_t unload_file(uint8_t** start, uint8_t** end) {
free(*start);
*start = NULL;
*end = NULL;
return 0;
}