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