1 /**
2 * @namespace biew_plugins_auto
3 * @file plugins/bin/lmf.c
4 * @brief This file contains implementation of lmf (QNX4 executable file)
5 * file format decoder.
6 * @version -
7 * @remark this source file is part of Binary vIEW project (BIEW).
8 * The Binary vIEW (BIEW) is copyright (C) 1995 Nickols_K.
9 * All rights reserved. This software is redistributable under the
10 * licence given in the file "Licence.en" ("Licence.ru" in russian
11 * translation) distributed in the BIEW archive.
12 * @note Requires POSIX compatible development system
13 *
14 * @author Andrew Golovnia
15 * @since 2001
16 * @note Development, fixes and improvements
17 * @todo wc 10.6 debug information support!!! (see lmf.tgz)
18 **/
19 #include <stddef.h>
20 #include <string.h>
21 #include <stdio.h>
22
23 #include "reg_form.h"
24 #include "bin_util.h"
25 #include "bmfile.h"
26 #include "biewhelp.h"
27 #include "biewutil.h"
28 #include "bconsole.h"
29 #include "plugins/disasm.h"
30 #include "plugins/bin/lmf.h"
31 #include "biewlib/biewlib.h"
32 #include "biewlib/kbd_code.h"
33 #include "biewlib/pmalloc.h"
34
35 #define MAXREC 200
36 #define MINREC 20
37 #define MAXSEG 50
38 #define MAXSEGFRAMES 50
39
40 typedef struct /* LMF file frame */
41 {
42 lmf_header header; /* Header of frame */
43 lmf_data data; /* Data info */
44 lmf_resource res; /* Resource info */
45 tUInt32 file_pos; /* Frame header file position */
46 } lmf_headers_list;
47
48 typedef struct /* Extra definition */
49 {
50 lmf_definition def; /* Standard definition */
51 tUInt32 seg[MAXSEG]; /* Segments lengthes list */
52 } lmf_xdef;
53
54 static lmf_headers_list *hl;
55 static lmf_xdef xdef;
56 static int xdef_len=0;
57 static unsigned seg_num=0;
58 static tUInt32 reccnt;
59 static tUInt32 recmax;
60 static tUInt32 reclast;
61 static tUInt32 segbase[MAXSEG];
62
63 char *lmftypes[]={
64 "definition",
65 "comment",
66 "text",
67 "fixup seg",
68 "fixup x87",
69 "eof",
70 "resource",
71 "end data",
72 "fixup linear",
73 "ph resource",
74 "unknown"};
75
failed_lmf(void)76 static void __FASTCALL__ failed_lmf(void)
77 {
78 /* lmf corruption message */
79 }
80
81 #define DEF xdef.def
82 #define DEFSIZE sizeof(lmf_definition)
83 #define DATSIZE sizeof(lmf_data)
84 #define HDRSIZE sizeof(lmf_header)
85
lmf_check_fmt(void)86 static tBool __FASTCALL__ lmf_check_fmt(void)
87 {
88 tInt32 i,j,p=0;
89 /* lmf_data d;*/
90 lmf_header h;
91 if(!bmReadBufferEx(&h,sizeof h,0,BM_SEEK_SET)) return False;
92 /* Test a first heder */
93 if(h.rec_type!=_LMF_DEFINITION_REC||h.zero1!=0||/*h.spare!=0||*/
94 h.data_nbytes<DEFSIZE+2*sizeof(long)||
95 (h.data_nbytes-DEFSIZE)%4!=0) return False;
96 i=j=(h.data_nbytes-DEFSIZE)/4;
97 xdef_len=h.data_nbytes;
98 if(!bmReadBufferEx(&xdef,min(sizeof(lmf_xdef),h.data_nbytes),6,BM_SEEK_SET)) return False;
99 /* Test a definition record */
100 if(DEF.version_no!=400||DEF.code_index>i||DEF.stack_index>i||
101 DEF.heap_index>i||DEF.argv_index>i||DEF.zero2!=0)
102 return False;
103 if(DEF.cpu%100!=86||(DEF.fpu!=0&&DEF.fpu%100!=87))
104 return False;
105 if(DEF.cflags&_PCF_FLAT&&DEF.flat_offset==0) return False;
106 if(DEF.stack_nbytes==0) return False;
107 for(i=0;i<4;i++)
108 if(DEF.zero1[i]!=0) return False;
109 while(1)
110 {
111 /* Test other headers */
112 p+=HDRSIZE+h.data_nbytes;
113 if(!bmReadBufferEx(&h,sizeof h,p,BM_SEEK_SET)) return False;
114 if(h.rec_type==_LMF_DEFINITION_REC||h.data_nbytes==0||
115 h.zero1!=0/*||h.spare!=0*/) return False;
116 if(h.rec_type==_LMF_EOF_REC) break;
117 }
118 return True;
119 }
120
121 #define failed_lmf {failed_lmf();return;}
122
lmf_init_fmt(void)123 static void __FASTCALL__ lmf_init_fmt(void)
124 {
125 tUInt32 i,l;
126 tInt32 pos=0;
127 hl=PMalloc(MINREC*sizeof(lmf_headers_list));
128 if(hl==NULL) return;
129 recmax=MINREC;
130 reccnt=0;
131 seg_num=(xdef_len-DEFSIZE)/4;
132 for(i=0;i<seg_num;i++) segbase[i]=0;
133 for(i=0;;i++)
134 {
135 if((unsigned)i==recmax)
136 {
137 hl=PRealloc(hl,(recmax+=MINREC)*sizeof(lmf_headers_list));
138 if(hl==NULL) return;
139 }
140 if(!bmReadBufferEx(&hl[i].header,HDRSIZE,pos,BM_SEEK_SET))
141 failed_lmf;
142 hl[i].file_pos=pos;
143 switch(hl[i].header.rec_type)
144 {
145 case _LMF_DATA_REC:
146 case _LMF_FIXUP_SEG_REC:
147 case _LMF_FIXUP_LINEAR_REC:
148 if(!bmReadBufferEx(&hl[i].data,DATSIZE,pos+HDRSIZE,BM_SEEK_SET))
149 failed_lmf;
150 l=hl[i].data.index;
151 if(l>=seg_num)
152 failed_lmf;
153 break;
154 case _LMF_RESOURCE_REC:
155 if(!bmReadBufferEx(&hl[i].res,sizeof(lmf_resource),pos+HDRSIZE,BM_SEEK_SET))
156 failed_lmf;
157 break;
158 case _LMF_EOF_REC:
159 reclast=i;
160 goto outloop;
161 case _LMF_DEFINITION_REC:
162 case _LMF_COMMENT_REC:
163 case _LMF_FIXUP_80X87_REC:
164 case _LMF_ENDDATA_REC: /* todo: decode license information (name) */
165 case _LMF_PHRESOURCE:
166 break; /* Ignore this records */
167 default:
168 failed_lmf;
169 }
170 pos+=hl[i].header.data_nbytes+HDRSIZE;
171 }
172 outloop:
173 if(DEF.cflags&_PCF_FLAT)
174 {
175 segbase[0]=DEF.stack_nbytes;
176 for(i=1;i<=seg_num;i++)
177 segbase[i]=(segbase[i-1]+
178 ((xdef.seg[i-1]&0x0fffffff)+4095))&0xfffff000;
179 }
180
181 return;
182 }
183
184 #undef failed_lmf
185
lmf_destroy_fmt(void)186 static void __FASTCALL__ lmf_destroy_fmt(void)
187 {
188 PFree(hl);
189 }
190
lmf_platform(void)191 static int __FASTCALL__ lmf_platform(void)
192 {
193 return DISASM_CPU_IX86;
194 }
195
lmf_bitness(__filesize_t pa)196 static int __FASTCALL__ lmf_bitness(__filesize_t pa)
197 {
198 UNUSED(pa);
199 if(DEF.cflags&_PCF_32BIT) return DAB_USE32;
200 else return DAB_USE16;
201 }
202
lmf_AddressResolv(char * addr,__filesize_t cfpos)203 static tBool __FASTCALL__ lmf_AddressResolv(char *addr,__filesize_t cfpos)
204 {
205 unsigned i;
206 /* Since this function is used in references resolving of disassembler
207 it must be seriously optimized for speed. */
208 for(i=0;i<=reclast;i++)
209 {
210 if(hl[i].file_pos<=cfpos&&
211 cfpos<hl[i].file_pos+hl[i].header.data_nbytes+HDRSIZE)
212 {
213 if(cfpos<hl[i].file_pos+HDRSIZE)
214 sprintf(addr,"H%s:%s",Get2Digit(i),Get4Digit(cfpos-hl[i].file_pos));
215 else
216 switch(hl[i].header.rec_type)
217 {
218 case _LMF_DEFINITION_REC:
219 sprintf(addr,"Def:%s",
220 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
221 break;
222 case _LMF_COMMENT_REC:
223 if(cfpos<hl[i].file_pos+HDRSIZE+DATSIZE)
224 sprintf(addr,"Com:%s",
225 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
226 break;
227 case _LMF_DATA_REC:
228 case _LMF_FIXUP_SEG_REC:
229 if(cfpos<hl[i].file_pos+HDRSIZE+DATSIZE)
230 sprintf(addr,(hl[i].header.rec_type==_LMF_DATA_REC)?
231 "Dat:%s":"Fix:%s",
232 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
233 /* else
234 if(((xdef.seg[hl[i].data.index]>>28)&0xf)==_LMF_CODE)
235 sprintf(addr,"C:%06X",(cfpos-hl[i].file_pos+
236 hl[i].data.offset-HDRSIZE-
237 DATSIZE));
238 else
239 sprintf(addr,"D:%06X",(cfpos-hl[i].file_pos+
240 hl[i].data.offset-HDRSIZE-
241 DATSIZE));*/
242 return False;
243 break;
244 case _LMF_FIXUP_80X87_REC:
245 sprintf(addr,"F87:%s",
246 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
247 break;
248 case _LMF_EOF_REC:
249 sprintf(addr,"Eof:%s",
250 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
251 break;
252 case _LMF_RESOURCE_REC:
253 sprintf(addr,"Res:%s",
254 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
255 break;
256 case _LMF_ENDDATA_REC:
257 sprintf(addr,"EnD:%s",
258 Get4Digit(cfpos-hl[i].file_pos-HDRSIZE));
259 break;
260 default:
261 return False;
262 }
263 return True;
264 }
265 }
266 return False;
267 }
268
lmf_va2pa(__filesize_t va)269 static __filesize_t __FASTCALL__ lmf_va2pa(__filesize_t va)
270 {
271 unsigned i,j;
272 int seclen;
273 __filesize_t addr=0;
274 __filesize_t newva=0;
275 if(DEF.cflags&_PCF_32BIT)
276 {
277 for(i=0;i<seg_num;i++)
278 if(va>segbase[i]&&va<segbase[i+1])
279 {
280 newva=va-segbase[i];
281 break;
282 }
283 if(newva>(xdef.seg[i]&0x0fffffff)) return 0;
284 }
285 else
286 {
287 i=va>>19;
288 newva=va&0xffff;
289 if(i>seg_num||newva>(xdef.seg[i]&0x0ffff)) return 0;
290 }
291 for(j=1;j<reclast;j++)
292 {
293 seclen=hl[j].header.data_nbytes-DATSIZE;
294 if(hl[j].header.rec_type==_LMF_DATA_REC&&
295 hl[j].data.index==i&&
296 hl[j].data.offset<=newva&&
297 hl[j].data.offset+seclen>newva) break;
298 }
299 if(i==reclast) return 0;
300 addr=hl[j].file_pos+newva-hl[j].data.offset+HDRSIZE+DATSIZE;
301
302 return addr;
303 }
304
lmf_pa2va(__filesize_t pa)305 static __filesize_t __FASTCALL__ lmf_pa2va(__filesize_t pa)
306 {
307 unsigned i;
308 int seclen;
309 __filesize_t addr=0;
310 for(i=1;i<reclast;i++)
311 {
312 seclen=hl[i].header.data_nbytes-DATSIZE;
313 if(hl[i].file_pos<=pa&&
314 hl[i].file_pos+seclen>pa)
315 {
316 if(hl[i].header.rec_type==_LMF_DATA_REC) break;
317 else return 0;
318 }
319 }
320 addr=hl[i].data.offset+pa-(hl[i].file_pos+HDRSIZE+DATSIZE);
321 if(DEF.cflags&_PCF_32BIT)
322 addr+=segbase[hl[i].data.index];
323 else
324 addr|=(hl[i].data.index<<19)|((DEF.cflags&_PCF_PRIVMASK)<<14);
325 return addr;
326 }
327
lmf_ReadSecHdr(BGLOBAL handle,memArray * obj,unsigned nnames)328 static tBool __FASTCALL__ lmf_ReadSecHdr(BGLOBAL handle,memArray *obj,unsigned nnames)
329 {
330 unsigned i;
331 char tmp[30];
332 char stmp[80];
333 UNUSED(handle);
334 UNUSED(nnames);
335 for(i=0;i<=reclast;i++)
336 {
337 switch(hl[i].header.rec_type)
338 {
339 case _LMF_DEFINITION_REC:
340 sprintf(tmp,"%s %s",
341 (DEF.cflags&_PCF_32BIT)?"32-bit":"16-bit",
342 (DEF.cflags&_PCF_FLAT)?"flat model":"");
343 sprintf(stmp," %2d %-17s<%2d> %s",i+1,
344 lmftypes[hl[i].header.rec_type],seg_num,tmp);
345 break;
346 case _LMF_DATA_REC:
347 case _LMF_FIXUP_SEG_REC:
348 case _LMF_FIXUP_LINEAR_REC:
349 sprintf(tmp,"%s (%s)",lmftypes[hl[i].header.rec_type],
350 ((xdef.seg[hl[i].data.index]>>28)==_LMF_CODE)?
351 "code":"data");
352 if(DEF.cflags&_PCF_32BIT)
353 sprintf(stmp," %2d %-18s %2d %08lX to %08lX",
354 i+1,
355 tmp,
356 hl[i].data.index,
357 (unsigned long)hl[i].data.offset,
358 (unsigned long)hl[i].data.offset+
359 hl[i].header.data_nbytes-HDRSIZE-DATSIZE);
360 else
361 sprintf(stmp," %2d %-18s %2d %04lX to %04lX ",
362 i+1,
363 tmp,
364 hl[i].data.index,
365 (unsigned long)hl[i].data.offset,
366 (unsigned long)hl[i].data.offset+
367 hl[i].header.data_nbytes-HDRSIZE-DATSIZE);
368 break;
369 case _LMF_RESOURCE_REC:
370 sprintf(tmp,"%s%s",lmftypes[hl[i].header.rec_type],
371 (hl[i].res.resource_type==0)?"(usage)":"");
372 sprintf(stmp," %2d %-18s",
373 i+1,tmp);
374 break;
375 default:
376 sprintf(stmp," %2d %-18s",i+1,
377 (hl[i].header.rec_type<10)?
378 lmftypes[hl[i].header.rec_type]:lmftypes[10]);
379 }
380 if(!ma_AddString(obj,stmp,True)) break;
381 }
382 return True;
383 }
384
lmf_SecHdrNumItems(BGLOBAL handle)385 static unsigned __FASTCALL__ lmf_SecHdrNumItems(BGLOBAL handle)
386 {
387 UNUSED(handle);
388 return reclast+1;
389 }
390
lmf_ShowSecLst(void)391 static __filesize_t __FASTCALL__ lmf_ShowSecLst(void)
392 {
393 __filesize_t fpos;
394 int ret;
395 fpos=BMGetCurrFilePos();
396 ret=fmtShowList(lmf_SecHdrNumItems,lmf_ReadSecHdr,
397 " Num Type Seg Virtual addresses ",
398 LB_SELECTIVE,NULL);
399 if(ret!=-1)
400 fpos=hl[ret].file_pos;
401 return fpos;
402 }
403
lmf_ShowHeader(void)404 static __filesize_t __FASTCALL__ lmf_ShowHeader( void )
405 {
406 unsigned i,j,k;
407 __filesize_t fpos;
408 TWindow *w;
409 char hdr[81];
410 char tmp[30];
411 unsigned keycode;
412 /* unsigned long entrya;*/
413 fpos = BMGetCurrFilePos();
414 sprintf(hdr," QNX%d Load Module Format Header ",DEF.version_no/100);
415 sprintf(tmp,"%s%sPrivity=%d%s%s",
416 (DEF.cflags&_PCF_LONG_LIVED)?"Long lived, ":"",
417 (DEF.cflags&_PCF_32BIT)?"32-bit, ":"",
418 (DEF.cflags&_PCF_PRIVMASK)>>2,
419 (DEF.cflags&_PCF_FLAT)?", Flat model":"",
420 (DEF.cflags&_PCF_NOSHARE)?", NoShare":"");
421 if(strlen(tmp)>30) j=5;
422 else j=1;
423 k=seg_num+j+1;
424 if(k<14) k=14;
425 w=CrtDlgWndnls(hdr,64,k);
426 twGotoXY(1,1);
427 twPrintF(
428 "Version = %d.%02d\n"
429 "Code flags = %04XH\n"
430 "(%s)\n"
431 "CPU/FPU = %d/%d\n",
432 DEF.version_no/100,DEF.version_no%100,DEF.cflags,
433 tmp,DEF.cpu,DEF.fpu);
434 twPrintF(
435 "Code index = %d\n"
436 "Stack index = %d\n"
437 "Heap index = %d\n"
438 "Argv index = %d\n"
439 "Code offset = %08lXH\n"
440 "Stack size = %08lXH\n"
441 "Heap size = %08lXH\n"
442 "Flat offset = %08lXH\n"
443 "Unmapped size = %08lXH\n",
444 DEF.code_index,
445 DEF.stack_index,
446 DEF.heap_index,
447 DEF.argv_index,
448 DEF.code_offset,
449 DEF.stack_nbytes,
450 DEF.heap_nbytes,
451 DEF.flat_offset,
452 DEF.unmapped_size);
453 twGotoXY(35,j++);
454 twPrintF("Segments:");
455 twGotoXY(35,j++);
456 twPrintF("Num Length Type");
457 for(i=0;i<seg_num;i++)
458 {
459 twGotoXY(35,j+i);
460 twPrintF(" %2d %08lXH %s",i,xdef.seg[i]&0x0fffffff,
461 ((xdef.seg[i]>>28)==_LMF_CODE)?
462 "code":"data");
463 }
464 twGotoXY(1,14);
465 twSetColorAttr(dialog_cset.entry);
466 twPrintF(
467 "Entry point = seg:%d, offset:%08lXH",
468 DEF.code_index,DEF.code_offset);
469 twClrEOL(); twPrintF("\n");
470 twSetColorAttr(dialog_cset.main);
471 while(1)
472 {
473 keycode=GetEvent(drawEmptyPrompt,NULL,w);
474 if(keycode==KE_ENTER)
475 {
476 if(DEF.cflags&_PCF_32BIT)
477 fpos=lmf_va2pa(segbase[DEF.code_index]+DEF.code_offset);
478 else
479 fpos=lmf_va2pa((DEF.code_index<<19)+DEF.code_offset);
480 break;
481 }
482 else
483 if(keycode==KE_ESCAPE||keycode==KE_F(10)) break;
484 }
485 CloseWnd(w);
486 return fpos;
487 }
488
lmf_LMFHlp(void)489 static __filesize_t __FASTCALL__ lmf_LMFHlp( void )
490 {
491 hlpDisplay(10015);
492 return BMGetCurrFilePos();
493 }
494
495 REGISTRY_BIN lmfTable=
496 {
497 "lmf (QNX4 executable file)",
498 {"LMFHlp",NULL,NULL,NULL,NULL,NULL,NULL,NULL,"SecLst",NULL},
499 {lmf_LMFHlp,NULL,NULL,NULL,NULL,NULL,NULL,NULL,lmf_ShowSecLst,NULL},
500 lmf_check_fmt,
501 lmf_init_fmt,
502 lmf_destroy_fmt,
503 lmf_ShowHeader,
504 NULL,
505 NULL,
506 lmf_platform,
507 lmf_bitness,
508 NULL,
509 lmf_AddressResolv,
510 lmf_va2pa,
511 lmf_pa2va,
512 NULL,
513 NULL,
514 NULL,
515 NULL
516 };
517