1 #include "BinRecord.hpp"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/fcntl.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9
10 // #define DEBUG
11
collectBinMap()12 int BinMapLoader::collectBinMap() {
13 uint8_t *data = struct_buffer;
14 size_t len = buffer_size;
15 size_t map_len = *(size_t *)(data + (len - sizeof(size_t)));
16 size_t map_offset = *(size_t *)(data + (len - sizeof(size_t) * 2));
17 size_t map_index = 0;
18 map_index_t *map_addr = NULL;
19 block_count = map_len;
20
21 map_addr = (map_index_t *)(data + map_offset);
22
23 block_vec.insert(block_vec.end(), data,
24 data + (uint64_t)map_addr[0].ptr_offset);
25
26 for (map_index = 0; map_index < map_len; map_index++) {
27 map_index_t tmap = (map_addr[map_index]);
28 map_vec.insert(map_vec.end(), (uint8_t *)&tmap,
29 (uint8_t *)&tmap + sizeof(map_index_t));
30
31 if (buffer_map[(uint64_t)tmap.ptr_offset]) {
32 #ifdef DEBUG
33 printf("skip:[%zu][%zu]!\n", map_index, (uint64_t)tmap.ptr_offset);
34 #endif
35 continue;
36 } else {
37 uint8_t *block_data = (uint64_t)tmap.ptr_offset + data;
38 buffer_map[(uint64_t)tmap.ptr_offset] = block_data;
39 uint64_t block_size = (uint64_t)tmap.len;
40 if (!block_data || block_size <= 0) {
41 printf("reduce error\n");
42 exit(0);
43 }
44 block_vec.insert(block_vec.end(), block_data, block_data + block_size);
45 }
46 }
47
48 return 0;
49 }
50
genBinary(void * buffer,size_t buffer_size)51 int BinMapLoader::genBinary(void *buffer, size_t buffer_size) {
52 if (buffer_size < block_vec.size() + map_vec.size()) {
53 printf("[BIN] buffer too small!\n");
54 return -1;
55 }
56
57 size_t map_offset = block_vec.size();
58 size_t map_len = map_vec.size() / sizeof(map_index_t);
59 size_t file_size = (block_vec.size() + map_vec.size() + sizeof(size_t) * 2);
60
61 memcpy(buffer, &block_vec[0], block_vec.size());
62 memcpy((uint8_t*)buffer + block_vec.size(), &map_vec[0], map_vec.size());
63 memcpy((uint8_t*)buffer + block_vec.size() + map_vec.size(), &map_offset,
64 sizeof(size_t));
65 memcpy((uint8_t*)buffer + block_vec.size() + map_vec.size() + sizeof(size_t),
66 &map_len, sizeof(map_len));
67
68 #ifdef DEBUG
69 printf("[BIN] file size:%ld, %ld, %ld\n", file_size, block_vec.size(),
70 map_vec.size());
71 #endif
72
73 return file_size;
74 }
75
dumpMap()76 int BinMapLoader::dumpMap() {
77 size_t curr_index = 0;
78
79 for (curr_index = 0; curr_index < block_count; curr_index++) {
80 map_index_t *temp_item =
81 (map_index_t *)&map_vec[curr_index * sizeof(map_index_t)];
82 #ifdef DEBUG
83 printf("[%ld]---dst:%ld-", curr_index, (uint64_t)temp_item->dst_offset);
84 printf("ptr:%ld-", (uint64_t)temp_item->ptr_offset);
85 printf("len:%ld\n", temp_item->len);
86 #endif
87
88 dst_map[(uint64_t)temp_item->dst_offset] = (void *)0xfffff;
89 }
90
91 return 0;
92 }
93
parseBinStructMap(uint8_t * data,size_t len)94 int BinMapLoader::parseBinStructMap(uint8_t *data, size_t len) {
95 size_t map_len = *(size_t *)(data + (len - sizeof(size_t)));
96 size_t map_offset = *(size_t *)(data + (len - sizeof(size_t) * 2));
97 size_t map_index = 0;
98 map_index_t *map_addr = NULL;
99
100 map_addr = (map_index_t *)(data + map_offset);
101
102 for (map_index = 0; map_index < map_len; map_index++) {
103 map_index_t tmap = (map_addr[map_index]);
104 void **dst_obj_addr = (void **)(data + (size_t)tmap.dst_offset);
105 *dst_obj_addr = data + (uintptr_t)tmap.ptr_offset;
106 #ifdef DEBUG
107 printf("ori[%ld]---dst:%ld-", map_index, (uint64_t)tmap.dst_offset);
108 printf("ptr:%ld-", (uint64_t)tmap.ptr_offset);
109 printf("len:%ld\n", tmap.len);
110 #endif
111 }
112
113 return 0;
114 }
115
compareBinStruct(map_index_t * binstruct1,map_index_t * binstruct2)116 int BinMapLoader::compareBinStruct(map_index_t *binstruct1,
117 map_index_t *binstruct2) {
118 if (!binstruct1 || !binstruct2) {
119 return -1;
120 }
121
122 if (binstruct1->len != binstruct2->len) {
123 return -1;
124 }
125
126 if (binstruct1->ptr_offset == binstruct2->ptr_offset) {
127 return -1;
128 }
129
130 void *first_obj = (uint64_t)binstruct1->ptr_offset + struct_buffer;
131 void *second_obj = (uint64_t)binstruct2->ptr_offset + struct_buffer;
132
133 if (0 == memcmp(first_obj, second_obj, binstruct1->len)) {
134 same_block += binstruct1->len;
135 #ifdef DEBUG
136 printf("[BIN] found same block:%zu\n", same_block);
137 #endif
138 return 0;
139 }
140
141 return -1;
142 }
143
loadWholeFile(const char * fpath,size_t * fsize)144 void *BinMapLoader::loadWholeFile(const char *fpath, size_t *fsize) {
145 struct stat st;
146 void *buf;
147 int fd;
148
149 if (!fpath || (0 != ::stat(fpath, &st))) {
150 printf("load bin file error!\n");
151 return NULL;
152 }
153
154 fd = open(fpath, O_RDONLY);
155 if (fd < 0) {
156 printf("failed to open: '%s'\n", fpath);
157 return NULL;
158 }
159
160 buf = malloc(st.st_size);
161 if (!buf) {
162 printf("read file oom!\n");
163 close(fd);
164 return NULL;
165 }
166
167 if (read(fd, buf, st.st_size) != st.st_size) {
168 printf("failed to read: '%s'\n", fpath);
169 free(buf);
170 close(fd);
171 return NULL;
172 }
173
174 *fsize = st.st_size;
175
176 close(fd);
177
178 return buf;
179 }
180
saveFile(const char * fpath,void * buf,size_t file_size)181 int BinMapLoader::saveFile(const char *fpath, void *buf, size_t file_size) {
182 FILE *ofp = NULL;
183
184 ofp = fopen(fpath, "wb+");
185 if (!ofp) {
186 printf("failed to open: '%s'\n", fpath);
187 return -1;
188 }
189
190 fwrite(buf, 1, file_size, ofp);
191 fclose(ofp);
192
193 return 0;
194 }
195
loadFile(const char * filename)196 int BinMapLoader::loadFile(const char *filename) {
197 struct_buffer = (uint8_t *)loadWholeFile(filename, &buffer_size);
198 if (!struct_buffer) {
199 printf("[BIN] load file faild!\n");
200 return -1;
201 }
202
203 return 0;
204 }
205
suqeezBinMapOne()206 int BinMapLoader::suqeezBinMapOne() {
207 int curr_index = block_count - 1;
208
209 for (curr_index = block_count - 1; curr_index > 0; curr_index--) {
210 map_index_t *map_item =
211 (map_index_t *)&map_vec[curr_index * sizeof(map_index_t)];
212 map_index_t *pre_item =
213 (map_index_t *)&map_vec[(curr_index - 1) * sizeof(map_index_t)];
214
215 // skip the already modfied item
216 if (pre_item->ptr_offset >= map_item->ptr_offset) {
217 continue;
218 }
219
220 if (map_item->len <= sizeof(void*) * 4) {
221 continue;
222 }
223
224 map_index_t same_item;
225 memset(&same_item, 0, sizeof(map_index_t));
226 if (0 == findDuplicate(map_item, curr_index, &same_item)) {
227 #ifdef DEBUG
228 printf("[BIN] remove map:[%d]\n", curr_index);
229 #endif
230 removeMap(map_item, curr_index);
231 removeBlock(map_item, curr_index, &same_item);
232 return 0;
233 }
234 }
235
236 return -1;
237 }
238
suqeezBinMap(const char * fpath,uint8_t * buffer,size_t buffer_len)239 int BinMapLoader::suqeezBinMap(const char *fpath, uint8_t *buffer,
240 size_t buffer_len) {
241 int ret = -1;
242 uint8_t *inp_buff = NULL;
243 uint8_t *out_buff = NULL;
244 size_t inp_size = 0;
245 size_t final_size = 0;
246
247 if (buffer_len > MAX_IQBIN_SIZE) {
248 printf("[BIN] %s %d:iq binary too large!\n", __func__, __LINE__);
249 return -1;
250 }
251
252 inp_buff = (uint8_t *)malloc(MAX_IQBIN_SIZE);
253 if (!inp_buff) {
254 printf("[BIN]%s %d:oom!\n", __func__, __LINE__);
255 return -1;
256 goto error;
257 }
258
259 out_buff = (uint8_t *)malloc(MAX_IQBIN_SIZE);
260 if (!out_buff) {
261 printf("[BIN] %s %d:oom!\n", __func__, __LINE__);
262 goto error;
263 }
264
265 memset(inp_buff, 0, MAX_IQBIN_SIZE);
266 memcpy(inp_buff, buffer, buffer_len);
267 inp_size = buffer_len;
268
269 do {
270 BinMapLoader *loader = new BinMapLoader(inp_buff, inp_size);
271 loader->parseBinStructMap(inp_buff, inp_size);
272 loader->collectBinMap();
273 ret = loader->suqeezBinMapOne();
274 memset(out_buff, 0, MAX_IQBIN_SIZE);
275 final_size = loader->genBinary(out_buff, MAX_IQBIN_SIZE);
276 memset(inp_buff, 0, MAX_IQBIN_SIZE);
277 memcpy(inp_buff, out_buff, MAX_IQBIN_SIZE);
278 inp_size = final_size;
279
280 if (ret != 0) {
281 loader->saveFile(fpath, out_buff, final_size);
282 }
283 } while (ret == 0);
284
285 error:
286 if (inp_buff) {
287 free(inp_buff);
288 }
289
290 if (out_buff) {
291 free(out_buff);
292 }
293
294 return 0;
295 }
296
findDuplicate(map_index_t * map_item,size_t map_index,map_index_t * ori_item)297 int BinMapLoader::findDuplicate(map_index_t *map_item, size_t map_index,
298 map_index_t *ori_item) {
299 size_t curr_index = 0;
300 if (map_index == 0) {
301 return -1;
302 }
303
304 for (curr_index = 0; curr_index < block_count; curr_index++) {
305 map_index_t *item =
306 (map_index_t *)&map_vec[curr_index * sizeof(map_index_t)];
307
308 if (0 == compareBinStruct(map_item, item)) {
309 #ifdef DEBUG
310 printf("[BIN][%ld]-", curr_index);
311 printf("duplicate-dst:%ld-", (uint64_t)item->dst_offset);
312 printf("ptr:%ld-", (uint64_t)item->ptr_offset);
313 printf("len:%ld\n", item->len);
314 #endif
315 *ori_item = *item;
316 return 0;
317 }
318 curr_index++;
319 if (curr_index >= map_index) {
320 return -1;
321 }
322 }
323
324 return -1;
325 }
326
removeBlock(map_index_t * map_item,size_t map_index,map_index_t * same_item)327 int BinMapLoader::removeBlock(map_index_t *map_item, size_t map_index,
328 map_index_t *same_item) {
329 int curr_index = 0;
330 if (map_index == 0) {
331 return -1;
332 }
333
334 uint64_t start_addr = (uint64_t)map_item->ptr_offset;
335 uint64_t end_addr = (uint64_t)map_item->ptr_offset + map_item->len;
336
337 #ifdef DEBUG
338 printf("fix ptr after:%ld\n", (uint64_t)map_item->ptr_offset);
339 #endif
340
341 for (curr_index = 0; curr_index < (int)block_count; curr_index++) {
342 map_index_t *temp_item =
343 (map_index_t *)&map_vec[curr_index * sizeof(map_index_t)];
344
345 uint64_t curr_dst = (uint64_t)temp_item->dst_offset;
346 uint64_t curr_ptr = (uint64_t)temp_item->ptr_offset;
347 int64_t d_diff = curr_dst - start_addr;
348 int64_t p_diff = curr_ptr - start_addr;
349
350 if (map_item->ptr_offset == temp_item->ptr_offset) {
351 if (map_item->dst_offset != temp_item->dst_offset)
352 temp_item->ptr_offset = same_item->ptr_offset;
353 }
354
355 #if 0
356 printf("diff is [%ld], [%ld]\n", d_diff, p_diff);
357 #endif
358
359 if (d_diff > 0) {
360 uint64_t new_offset = (uint64_t)temp_item->dst_offset - same_item->len;
361 temp_item->dst_offset = (void *)new_offset;
362 }
363
364 if (p_diff > 0) {
365 uint64_t new_offset = (uint64_t)temp_item->ptr_offset - same_item->len;
366 temp_item->ptr_offset = (void *)new_offset;
367 }
368 }
369
370 map_item->ptr_offset = same_item->ptr_offset;
371 map_item->len = 0;
372 block_vec.erase(block_vec.begin() + start_addr, block_vec.begin() + end_addr);
373
374 return 0;
375 }
376
removeMap(map_index_t * map_item,size_t map_index)377 int BinMapLoader::removeMap(map_index_t *map_item, size_t map_index) {
378 size_t curr_index = 0;
379 if (map_index == 0) {
380 return -1;
381 }
382
383 uint64_t start_addr = (uint64_t)map_item->ptr_offset;
384 uint64_t end_addr = (uint64_t)map_item->ptr_offset + map_item->len;
385
386 for (curr_index = 0; curr_index < block_count; curr_index++) {
387 map_index_t *temp_item =
388 (map_index_t *)&map_vec[curr_index * sizeof(map_index_t)];
389 if ((uint64_t)temp_item->dst_offset >= start_addr &&
390 (uint64_t)temp_item->dst_offset < end_addr) {
391 #ifdef DEBUG
392 printf("[BIN]remove the map->%d\n", curr_index);
393 #endif
394 map_vec.erase(map_vec.begin() + curr_index * sizeof(map_index_t),
395 map_vec.begin() + (1 + curr_index) * sizeof(map_index_t));
396 block_count--;
397 }
398 }
399
400 return 0;
401 }
402
info()403 void BinMapLoader::info() {
404 printf("block info:[%zu]\n", block_vec.size());
405 printf("map info:[%zu]\n", map_vec.size());
406 }
407
408