1 /*
2  *	HT Editor
3  *	analy.cc
4  *
5  *	Copyright (C) 1999-2002 Sebastian Biallas (sb@biallas.net)
6  *
7  *	This program is free software; you can redistribute it and/or modify
8  *	it under the terms of the GNU General Public License version 2 as
9  *	published by the Free Software Foundation.
10  *
11  *	This program is distributed in the hope that it will be useful,
12  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *	GNU General Public License for more details.
15  *
16  *	You should have received a copy of the GNU General Public License
17  *	along with this program; if not, write to the Free Software
18  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 
25 #include "analy.h"
26 #include "analy_names.h"
27 #include "analy_register.h"
28 #include "code_analy.h"
29 #include "data_analy.h"
30 #include "io/types.h"
31 #include "atom.h"
32 #include "except.h"
33 #include "htctrl.h"
34 #include "htdebug.h"
35 #include "strtools.h"
36 #include "language.h"
37 #include "snprintf.h"
38 #include "tools.h"
39 
40 #define DPRINTF(msg...)
41 //#undef DPRINTF
42 //#define DPRINTF(msg...) {global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;char buf[1024]; ht_snprintf(buf, sizeof buf, ##msg); fprintf(stdout, buf);}
43 
44 int global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT;
45 
compareDelinear(Address * obj)46 int Address::compareDelinear(Address *obj)
47 {
48 	return compareTo(obj);
49 }
50 
isValid()51 bool Address::isValid()
52 {
53 	return true;
54 }
55 
toString(char * s,int maxlen) const56 int Address::toString(char *s, int maxlen) const
57 {
58 	return stringify(s, maxlen, global_analyser_address_string_format);
59 }
60 
add(int offset)61 bool InvalidAddress::add(int offset)
62 {
63 	return false;
64 }
65 
byteSize()66 int InvalidAddress::byteSize()
67 {
68 	return 0;
69 }
70 
compareTo(const Object * obj) const71 int InvalidAddress::compareTo(const Object *obj) const
72 {
73 	return 0;
74 }
75 
putIntoCPUAddress(CPU_ADDR * ca) const76 void InvalidAddress::putIntoCPUAddress(CPU_ADDR *ca) const
77 {
78 }
79 
difference(int & result,Address * to)80 bool InvalidAddress::difference(int &result, Address *to)
81 {
82 	return false;
83 }
84 
clone() const85 InvalidAddress *InvalidAddress::clone() const
86 {
87 	return new InvalidAddress(*this);
88 }
89 
getFromArray(const byte * array)90 void InvalidAddress::getFromArray(const byte *array)
91 {
92 }
93 
getFromCPUAddress(CPU_ADDR * ca)94 void InvalidAddress::getFromCPUAddress(CPU_ADDR *ca)
95 {
96 }
97 
getFromUInt64(uint64 u)98 bool InvalidAddress::getFromUInt64(uint64 u)
99 {
100 	return false;
101 }
102 
isValid()103 bool InvalidAddress::isValid()
104 {
105 	return false;
106 }
107 
parseString(const char * s,int length,Analyser * a)108 int InvalidAddress::parseString(const char *s, int length, Analyser *a)
109 {
110 	return 0;
111 }
112 
getObjectID() const113 ObjectID InvalidAddress::getObjectID() const
114 {
115 	return ATOM_ADDRESS_INVALID;
116 }
117 
putIntoArray(byte * array) const118 void InvalidAddress::putIntoArray(byte *array) const
119 {
120 }
121 
putIntoUInt64(uint64 & u) const122 bool InvalidAddress::putIntoUInt64(uint64 &u) const
123 {
124 	return false;
125 }
126 
stringify(char * s,int max_length,int format) const127 int InvalidAddress::stringify(char *s, int max_length, int format) const
128 {
129 	return ht_snprintf(s, max_length, "*INVALID");
130 }
131 
stringSize() const132 int InvalidAddress::stringSize() const
133 {
134 	return 8;
135 }
136 
137 /*
138  *
139  */
add(int offset)140 bool AddressFlat32::add(int offset)
141 {
142 	// check for overflow
143 	if ((int)offset < 0) {
144 		if (addr+offset > addr) return false;
145 	} else {
146 		if (addr+offset < addr) return false;
147 	}
148 	addr+=offset;
149 	return true;
150 }
151 
byteSize()152 int AddressFlat32::byteSize()
153 {
154 	return 4;
155 }
156 
compareTo(const Object * obj) const157 int AddressFlat32::compareTo(const Object *obj) const
158 {
159 	assert(getObjectID() == obj->getObjectID());
160 	if (addr > ((AddressFlat32 *)obj)->addr) return 1;
161 	if (addr < ((AddressFlat32 *)obj)->addr) return -1;
162 	return 0;
163 }
164 
compareDelinear(Address * to)165 int AddressFlat32::compareDelinear(Address *to)
166 {
167 	assert(getObjectID() == to->getObjectID());
168 	uint32 da = delinearize(addr);
169 	uint32 db = delinearize(((AddressFlat32 *)to)->addr);
170 	if (da > db) return 1;
171 	if (da < db) return -1;
172 	return 0;
173 }
174 
difference(int & result,Address * to)175 bool AddressFlat32::difference(int &result, Address *to)
176 {
177 	if (getObjectID() == to->getObjectID()) {
178 		result = addr - ((AddressFlat32 *)to)->addr;
179 		return true;
180 	} else {
181 		return false;
182 	}
183 }
184 
clone() const185 AddressFlat32 *AddressFlat32::clone() const
186 {
187 	return new AddressFlat32(*this);
188 }
189 
getFromArray(const byte * array)190 void AddressFlat32::getFromArray(const byte *array)
191 {
192 	memcpy(&addr, array, sizeof(addr));
193 }
194 
getFromCPUAddress(CPU_ADDR * ca)195 void AddressFlat32::getFromCPUAddress(CPU_ADDR *ca)
196 {
197 	addr = ca->addr32.offset;
198 }
199 
getFromUInt64(uint64 u)200 bool AddressFlat32::getFromUInt64(uint64 u)
201 {
202 	if (u <= 0xffffffff) {
203 		addr = u;
204 		return true;
205 	} else {
206 		return false;
207 	}
208 }
209 
load(ObjectStream & st)210 void AddressFlat32::load(ObjectStream &st)
211 {
212 	GET_INT32X(st, addr);
213 }
214 
getObjectID() const215 ObjectID AddressFlat32::getObjectID() const
216 {
217 	return ATOM_ADDRESS_FLAT_32;
218 }
219 
parseString(const char * s,int length,Analyser * a)220 int AddressFlat32::parseString(const char *s, int length, Analyser *a)
221 {
222 	return false;
223 }
224 
putIntoArray(byte * array) const225 void AddressFlat32::putIntoArray(byte *array) const
226 {
227 	memcpy(array, &addr, sizeof(addr));
228 }
229 
putIntoCPUAddress(CPU_ADDR * ca) const230 void AddressFlat32::putIntoCPUAddress(CPU_ADDR *ca) const
231 {
232 	ca->addr32.offset = addr;
233 }
234 
putIntoUInt64(uint64 & u) const235 bool AddressFlat32::putIntoUInt64(uint64 &u) const
236 {
237 	u = addr;
238 	return true;
239 }
240 
store(ObjectStream & st) const241 void AddressFlat32::store(ObjectStream &st) const
242 {
243 	PUT_INT32X(st, addr);
244 }
245 
stringify(char * s,int max_length,int format) const246 int AddressFlat32::stringify(char *s, int max_length, int format) const
247 {
248 	const char *formats[] = {
249 		"%s%x%s",
250 		"%s%8x%s",
251 		"%s%08x%s",
252 		"",
253 		"%s%X%s",
254 		"%s%8X%s",
255 		"%s%08X%s",
256 		"",
257 	};
258 	return ht_snprintf(s, max_length, formats[format&7], (format & ADDRESS_STRING_FORMAT_ADD_0X) ? "0x":"", addr, (format & ADDRESS_STRING_FORMAT_ADD_H) ? "h":"");
259 }
260 
stringSize() const261 int AddressFlat32::stringSize() const
262 {
263 	return 8;
264 }
265 
266 /*
267  *
268  */
add(int offset)269 bool AddressFlat64::add(int offset)
270 {
271 	// check for overflow
272 	// FIXME: XXXXXXXXXXXXX
273 	addr += sint64(offset);
274 	return true;
275 }
276 
byteSize()277 int AddressFlat64::byteSize()
278 {
279 	return 8;
280 }
281 
compareTo(const Object * obj) const282 int AddressFlat64::compareTo(const Object *obj) const
283 {
284 	assert(getObjectID() == obj->getObjectID());
285 	if (addr > ((AddressFlat64 *)obj)->addr) return 1;
286 	if (addr < ((AddressFlat64 *)obj)->addr) return -1;
287 	return 0;
288 }
289 
compareDelinear(Address * to)290 int AddressFlat64::compareDelinear(Address *to)
291 {
292 	assert(getObjectID() == to->getObjectID());
293 	uint64 da1, da2;
294 	da1 = delinearize64(addr);
295 	da2 = delinearize64(((AddressFlat64 *)to)->addr);
296 	if (da1 > da2) return 1;
297 	if (da1 < da2) return -1;
298 	return 0;
299 }
300 
difference(int & result,Address * to)301 bool AddressFlat64::difference(int &result, Address *to)
302 {
303 	if (getObjectID() == to->getObjectID()) {
304 		uint64 res = addr - ((AddressFlat64 *)to)->addr;
305 		uint32 rh = res >> 32;
306 		if (!rh || rh == 0xffffffff) {
307 			result = res;
308 			return true;
309 		}
310 	}
311 	return false;
312 }
313 
clone() const314 AddressFlat64 *AddressFlat64::clone() const
315 {
316 	return new AddressFlat64(*this);
317 }
318 
getFromArray(const byte * array)319 void AddressFlat64::getFromArray(const byte *array)
320 {
321 	memcpy(&addr, array, sizeof(addr));
322 }
323 
getFromCPUAddress(CPU_ADDR * ca)324 void AddressFlat64::getFromCPUAddress(CPU_ADDR *ca)
325 {
326 	addr = ca->flat64.addr;
327 }
328 
getFromUInt64(uint64 u)329 bool AddressFlat64::getFromUInt64(uint64 u)
330 {
331 	addr = u;
332 	return true;
333 }
334 
load(ObjectStream & st)335 void AddressFlat64::load(ObjectStream &st)
336 {
337 	GET_INT64X(st, addr);
338 }
339 
getObjectID() const340 ObjectID AddressFlat64::getObjectID() const
341 {
342 	return ATOM_ADDRESS_FLAT_64;
343 }
344 
parseString(const char * s,int length,Analyser * a)345 int AddressFlat64::parseString(const char *s, int length, Analyser *a)
346 {
347 	return false;
348 }
349 
putIntoArray(byte * array) const350 void AddressFlat64::putIntoArray(byte *array) const
351 {
352 	memcpy(array, &addr, sizeof(addr));
353 }
354 
putIntoCPUAddress(CPU_ADDR * ca) const355 void AddressFlat64::putIntoCPUAddress(CPU_ADDR *ca) const
356 {
357 	ca->flat64.addr = addr;
358 }
359 
putIntoUInt64(uint64 & u) const360 bool AddressFlat64::putIntoUInt64(uint64 &u) const
361 {
362 	u = addr;
363 	return true;
364 }
365 
store(ObjectStream & st) const366 void AddressFlat64::store(ObjectStream &st) const
367 {
368 	PUT_INT64X(st, addr);
369 }
370 
stringify(char * s,int max_length,int format) const371 int AddressFlat64::stringify(char *s, int max_length, int format) const
372 {
373 	const char *formats[] = {
374 		"%s%qx%s",
375 		"%s%16qx%s",
376 		"%s%016qx%s",
377 		"",
378 		"%s%qx%s",
379 		"%s%16qx%s",
380 		"%s%016qx%s",
381 		"",
382 	};
383 	return ht_snprintf(s, max_length, formats[format&7], (format & ADDRESS_STRING_FORMAT_ADD_0X) ? "0x":"", addr, (format & ADDRESS_STRING_FORMAT_ADD_H) ? "h":"");
384 }
385 
stringSize() const386 int AddressFlat64::stringSize() const
387 {
388 	return 16;
389 }
390 
391 
392 /*
393  *
394  */
395 
AddrXRef(Address * a,xref_enum_t Type)396 AddrXRef::AddrXRef(Address *a, xref_enum_t Type)
397 {
398 	addr = a->clone();
399 	type = Type;
400 }
401 
~AddrXRef()402 AddrXRef::~AddrXRef()
403 {
404 	delete addr;
405 }
406 
load(ObjectStream & f)407 void AddrXRef::load(ObjectStream &f)
408 {
409 	GET_OBJECT(f, addr);
410 	type = (xref_enum_t)GETX_INTX(f, 1, "type");
411 }
412 
getObjectID() const413 ObjectID AddrXRef::getObjectID() const
414 {
415 	return ATOM_ADDR_XREF;
416 }
417 
store(ObjectStream & f) const418 void AddrXRef::store(ObjectStream &f) const
419 {
420 	PUT_OBJECT(f, addr);
421 	PUT_INTX(f, type, 1);
422 }
423 
compareTo(const Object * o) const424 int AddrXRef::compareTo(const Object *o) const
425 {
426 	Address *a = ((AddrXRef*)o)->addr;
427 	return addr->compareTo(a);
428 }
429 
430 /*
431  *
432  */
AddressQueueItem(Address * aAddr,Address * aFunc)433 AddressQueueItem::AddressQueueItem(Address *aAddr, Address *aFunc)
434 {
435 	addr = aAddr->clone();
436 	func = aFunc->clone();
437 }
438 
~AddressQueueItem()439 AddressQueueItem::~AddressQueueItem()
440 {
441 	delete addr;
442 	delete func;
443 }
444 
getObjectID() const445 ObjectID AddressQueueItem::getObjectID() const
446 {
447 	return ATOM_ADDR_QUEUE_ITEM;
448 }
449 
load(ObjectStream & f)450 void AddressQueueItem::load(ObjectStream &f)
451 {
452 	GET_OBJECT(f, addr);
453 	GET_OBJECT(f, func);
454 }
455 
store(ObjectStream & f) const456 void	AddressQueueItem::store(ObjectStream &f) const
457 {
458 	PUT_OBJECT(f, addr);
459 	PUT_OBJECT(f, func);
460 }
461 
462 /*
463  *
464  */
CommentList()465 CommentList::CommentList()
466 	: Array(true)
467 {
468 }
469 
appendPreComment(const char * s)470 void CommentList::appendPreComment(const char *s)
471 {
472 	insert(new String(s));
473 }
474 
appendPostComment(const char * s)475 void CommentList::appendPostComment(const char *s)
476 {
477 	insert(new String(s));
478 }
479 
appendPreComment(int special)480 void CommentList::appendPreComment(int special)
481 {
482 	insert(new UInt(special));
483 }
484 
appendPostComment(int special)485 void CommentList::appendPostComment(int special)
486 {
487 	insert(new UInt(special+0x10000000));
488 }
489 
getName(uint i)490 const char *CommentList::getName(uint i)
491 {
492 	Object *d = get(findByIdx(i));
493 //	return d ? ((d->getObjectID()==OBJID_UINT) ? comment_lookup(((UInt*)d)->value):
494 	return d ? ((String*)d)->contentChar() : NULL;
495 }
496 
497 /*
498  *
499  */
init()500 void	Analyser::init()
501 {
502 	active = false;
503 	dirty = false;
504 	next_address_is_invalid = false;
505 	addr = new InvalidAddress();
506 	invalid_addr = new InvalidAddress();
507 	addr_queue = new Queue(true);
508 	locations = NULL;
509 	symbols = NULL;
510 	symbol_count = location_count = 0;
511 	cur_addr_ops = cur_label_ops = 1;
512 	setLocationTreeOptimizeThreshold(1000);
513 	setSymbolTreeOptimizeThreshold(1000);
514 	cur_func = NULL;
515 	ops_parsed = 0;
516 	next_explored = new InvalidAddress();
517 	first_explored = new InvalidAddress();
518 	last_explored = new InvalidAddress();
519 	explored = new Area();
520 	explored->init();
521 	initialized = new Area();
522 	initialized->init();
523 	initCodeAnalyser();
524 	initDataAnalyser();
525 	disasm = NULL;
526 	analy_disasm = NULL;
527 	max_opcode_length = 1;
528 	initUnasm();
529 	mode = ANALY_TRANSLATE_SYMBOLS;
530 }
531 
loadlocations(ObjectStream & st,Location * & loc,int l,int r)532 static void loadlocations(ObjectStream &st, Location *&loc, int l, int r)
533 {
534 	if (l > r) {
535 		loc = NULL;
536 		return;
537 	}
538 	int m = (l+r)/2;
539 	loc = new Location;
540 
541 	loadlocations(st, loc->left, l, m-1);
542 
543 	loc->addr = GETX_OBJECT(st , "addr");
544 
545 	// xrefs
546 	loc->xrefs = GETX_OBJECT(st, "xrefs");
547 
548 	// comments
549 	loc->comments = GETX_OBJECT(st, "comments");
550 
551 	analyser_get_addrtype(st, &loc->type);
552 
553 	// must be resolved later (thisfunc is of type Location not Address)
554 	Address *a = GETX_OBJECT(st, "func");
555 	loc->thisfunc = (Location *)a;
556 	loc->flags = GETX_INT(st, 1, "flags");
557 	loc->label = NULL;
558 
559 	loadlocations(st, loc->right, m+1, r);
560 }
561 
loadsymbols(Analyser * analy,ObjectStream & st,Symbol * & symbol,int l,int r)562 static void loadsymbols(Analyser *analy, ObjectStream &st, Symbol *&symbol, int l, int r)
563 {
564 	if (l > r) {
565 		symbol = NULL;
566 		return;
567 	}
568 	int m = (l+r)/2;
569 	symbol = new Symbol;
570 
571 	loadsymbols(analy, st, symbol->left, l, m-1);
572 
573 	Address *a = GETX_OBJECT(st, "addr");
574 
575 	(symbol->location = analy->newLocation(a))->label = symbol;
576 	delete a;
577 
578 	symbol->name = st.getString("name");
579 
580 	symbol->type = (labeltype)GETX_INT(st, 1, "type");
581 
582 	loadsymbols(analy, st, symbol->right, m+1, r);
583 }
584 
resolveaddrs(Analyser * a,Location * loc)585 static void resolveaddrs(Analyser *a, Location *loc)
586 {
587 	if (loc) {
588 		resolveaddrs(a, loc->left);
589 		Address *tmp = (Address*)loc->thisfunc;
590 		if (tmp->isValid()) {
591 			loc->thisfunc = a->getLocationByAddress(tmp);
592 		} else {
593 			loc->thisfunc = NULL;
594 		}
595 		delete tmp;
596 		resolveaddrs(a, loc->right);
597 	}
598 }
599 
600 /*
601  *
602  */
load(ObjectStream & st)603 void Analyser::load(ObjectStream &st)
604 {
605 	cur_addr_ops = 0;
606 	cur_label_ops = 0;
607 	GET_OBJECT(st, addr);
608 	invalid_addr = new InvalidAddress();
609 	GET_OBJECT(st, addr_queue);
610 	GET_INT32D(st, ops_parsed);
611 	GET_BOOL(st, active);
612 	if (active) {
613 		some_analyser_active++;
614 	}
615 	next_address_is_invalid = false;
616 	GET_OBJECT(st, next_explored);
617 	GET_OBJECT(st, first_explored);
618 	GET_OBJECT(st, last_explored);
619 
620 	GET_INT32X(st, mode);
621 
622 	GET_OBJECT(st, explored);
623 	GET_OBJECT(st, initialized);
624 
625 	cur_addr_ops = cur_label_ops = 1;
626 	setLocationTreeOptimizeThreshold(1000);
627 	setSymbolTreeOptimizeThreshold(1000);
628 
629 	GET_INT32D(st, location_count);
630 	loadlocations(st, locations, 0, location_count-1);
631 
632 	resolveaddrs(this, locations);
633 
634 	GET_INT32D(st, symbol_count);
635 	loadsymbols(this, st, symbols, 0, symbol_count-1);
636 
637 	GET_OBJECT(st, analy_disasm);
638 	GET_OBJECT(st, disasm);
639 	if (analy_disasm) {
640 		analy_disasm->analy = this;
641 		analy_disasm->disasm = disasm;
642 	}
643 	GET_OBJECT(st, code);
644 	GET_OBJECT(st, data);
645 	if (data) {
646 		data->analy = this;
647 	}
648 	GET_INT32D(st, location_threshold);
649 	GET_INT32D(st, symbol_threshold);
650 
651 	GET_INT32D(st, max_opcode_length);
652 
653 	Address *curfuncaddr = GETX_OBJECT(st, "cur_func");
654 	if (curfuncaddr) {
655 		cur_func = newLocation(curfuncaddr);
656 		delete curfuncaddr;
657 	} else {
658 		cur_func = NULL;
659 	}
660 
661 	dirty = false;
662 }
663 
664 /*
665  *
666  */
done()667 void	Analyser::done()
668 {
669 	setActive(false);
670 	freeLocations(locations);
671 	freeSymbols(symbols);
672 	delete addr_queue;
673 	if (explored) {
674 		explored->done();
675 		delete explored;
676 	}
677 	if (initialized) {
678 		initialized->done();
679 		delete initialized;
680 	}
681 	if (code) {
682 		code->done();
683 		delete code;
684 	}
685 	if (data) {
686 		data->done();
687 		delete data;
688 	}
689 	if (disasm) {
690 		disasm->done();
691 		delete disasm;
692 	}
693 	if (analy_disasm) {
694 		analy_disasm->done();
695 		delete analy_disasm;
696 	}
697 	delete addr;
698 	delete invalid_addr;
699 	delete next_explored;
700 	delete first_explored;
701 	delete last_explored;
702 }
703 
704 /*
705  *	addAddressSymbol will never overwrite an existing label (like addlabel)
706  */
addAddressSymbol(Address * address,const char * prefix,labeltype type,Location * infunc)707 bool Analyser::addAddressSymbol(Address *address, const char *prefix, labeltype type, Location *infunc)
708 {
709 	if (!validAddress(address, scvalid)) return false;
710 
711 	char symbol[1024];
712 	global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT;
713 	ht_snprintf(symbol, sizeof symbol, "%s_%y", prefix, address);
714 
715 	if (addSymbol(address, symbol, type, infunc)) {
716 		return true;
717 	} else {
718 		return false;
719 	}
720 }
721 
722 /*
723  *
724  */
addComment(Address * Addr,int line,const char * c)725 void	Analyser::addComment(Address *Addr, int line, const char *c)
726 {
727 	// line 0 meens append (at the moment assume append every time ;-))
728 
729 //	if (!validaddr(Addr, scvalid)) return;
730 
731 	Location *a = newLocation(Addr);
732 
733 	CommentList *com = a->comments;
734 
735 	if (!com) {
736 		com = new CommentList();
737 		com->init();
738 		a->comments = com;
739 	}
740 	com->appendPreComment(c);
741 
742 	DPRINTF("#(%y) comment `%s'\n", Addr, c);
743 }
744 
745 /*
746  * addlabel: create label if there isnt one
747  *           fail if label exist on another address
748  *
749  */
addSymbol(Address * Addr,const char * label,labeltype type,Location * infunc)750 bool Analyser::addSymbol(Address *Addr, const char *label, labeltype type, Location *infunc)
751 {
752 	if (!validAddress(Addr, scvalid)) return false;
753 
754 	Location *a = newLocation(Addr);
755 
756 	if (!a->label) {
757 
758 		Symbol *l = newSymbol(label, a, type, infunc);
759 
760 		if (l->location->addr->compareTo(Addr) != 0) {
761 			// this label already exists at a different address
762 			return false;
763 		}
764 
765 		a->label = l;
766 		if (a->type.type == dt_unknown || a->type.type == dt_unknown_data) {
767 			if (type == label_func && !validCodeAddress(Addr)) {
768 				type = label_unknown;
769 			}
770 			switch (type) {
771 				case label_unknown:
772 					break;
773 				case label_func:
774 					data->setCodeAddressType(a, dst_function);
775 					break;
776 				case label_loc:
777 					data->setCodeAddressType(a, dst_location);
778 					break;
779 				case label_data:
780 					data->setAddressType(a, dt_unknown_data, 0, 0);
781 					break;
782 			}
783 		}
784 		return true;
785 
786 	} else {
787 
788 		// adress already has a label
789 		return false;
790 	}
791 }
792 
793 /*
794  *
795  */
addXRef(Address * from,Address * to,xref_enum_t action)796 bool Analyser::addXRef(Address *from, Address *to, xref_enum_t action)
797 {
798 	if (!validAddress(from, scvalid) || !validAddress(to, scvalid)) return false;
799 
800 	Location *a = newLocation(from);
801 	Container *x = a->xrefs;
802 
803 	if (x) {
804 		AddrXRef tmp(to);
805 		if (x->find(&tmp)) return false;
806 	} else {
807 		x = new AVLTree(true);
808 		a->xrefs = x;
809 	}
810 	x->insert(new AddrXRef(to, action));
811 
812 	DPRINTF("xref %y->%y\n", from, to);
813 	return true;
814 }
815 
816 /*
817  *
818  */
assignComment(Address * Addr,int line,const char * c)819 void	Analyser::assignComment(Address *Addr, int line, const char *c)
820 {
821 	/* not really implemented */
822 	addComment(Addr, line, c);
823 }
824 
825 /*
826  *
827  */
assignSymbol(Address * Addr,const char * label,labeltype type,Location * infunc)828 bool Analyser::assignSymbol(Address *Addr, const char *label, labeltype type, Location *infunc)
829 {
830 	if (!validAddress(Addr, scvalid)) return false;
831 
832 	Location *a = newLocation(Addr);
833 
834 	Symbol *l = newSymbol(label, a, type, infunc);
835 	if (l->location->addr->compareTo(Addr) != 0) {
836 		// label already exists at a different address
837 		return false;
838 	}
839 
840 	if (l->location->type.type == dt_unknown) {
841 		if (type == label_func && !validCodeAddress(Addr)) {
842 			type = label_unknown;
843 		}
844 		switch (type) {
845 			case label_unknown:
846 				break;
847 			case label_func:
848 				data->setCodeAddressType(a, dst_function);
849 				break;
850 			case label_loc:
851 				data->setCodeAddressType(a, dst_location);
852 				break;
853 			case label_data:
854 				data->setAddressType(a, dt_unknown_data, 0, 0);
855 				break;
856 		}
857 	}
858 
859 	if (a->label) {
860 		// overwrite
861 		if (a->label != l) {
862 			// label has to be renamed
863 			disableSymbol(a->label);
864 			a->label = l;
865 		}
866 	} else {
867 		a->label = l;
868 	}
869 	return true;
870 }
871 
872 /*
873  *
874  */
assignXRef(Address * from,Address * to,xref_enum_t action)875 void Analyser::assignXRef(Address *from, Address *to, xref_enum_t action)
876 {
877 	if (!validAddress(from, scvalid) || !validAddress(to, scvalid)) return;
878 
879 	Location	*a = newLocation(from);
880 	Container	*x = a->xrefs;
881 
882 	if (x) {
883 		AddrXRef *xref;
884 		AddrXRef tmp(to);
885 		if ((xref = (AddrXRef*)x->get(x->find(&tmp)))) {
886 			// update xref
887 			xref->type = action;
888 			DPRINTF("xref %y->%y updated\n", from, to);
889 			return;
890 		}
891 	} else {
892 		x = new AVLTree(true);
893 		a->xrefs = x;
894 	}
895 	x->insert(new AddrXRef(to, action));
896 
897 	DPRINTF("xref %y->%y\n", from, to);
898 }
899 
900 /*
901  *
902  */
beginAnalysis()903 void	Analyser::beginAnalysis()
904 {
905 	if (queryConfig(Q_DO_ANALYSIS)) {
906 		DPRINTF("################################\nAnalysis started.\n");
907 		if (analy_disasm && disasm) {
908 			ops_parsed = 0;
909 			if (gotoAddress(invalid_addr, invalid_addr)) setActive(true);
910 		} else {
911 			DPRINTF("Analysis can't be started. No disassembler available.");
912 		}
913 	}
914 }
915 
916 /*
917  *
918  */
continueAnalysis()919 bool	Analyser::continueAnalysis()
920 {
921 	byte			buf[32];
922 	OPCODE		*instr;
923 	int			len;
924 	branch_enum_t	branch;
925 
926 	assert((uint)max_opcode_length <= sizeof buf);
927 
928 	if (!active) return	false;
929 	do {
930 
931 		int diff;
932 //		char tbuf[100];
933 //		char tbuf2[100];
934 //		addr->stringify(tbuf, 100, 0);
935 /*		if (strcmp(tbuf, "200970ec") == 0) {
936 			int as=0;
937 		}*/
938 //		printf("*** %s ***\n", tbuf);
939 		if ((addr->difference(diff, next_explored) && (diff >= 0)) || !validCodeAddress(addr)) {
940 			if (!gotoAddress(addr, invalid_addr)) {
941 				finish();
942 				return false;
943 			}
944 		}
945 
946 		int bz = bufPtr(addr, buf, max_opcode_length);
947 
948 		instr = disasm->decode(buf, bz, mapAddr(addr));
949 		instr = disasm->duplicateInsn(instr);
950 
951 		ops_parsed++;
952 		num_ops_parsed++;
953 
954 		len = disasm->getSize(instr);
955 		last_explored->add(len);
956 
957 		do {
958 			DPRINTF("opcode @%y [func: %y]: %s\n", addr, (cur_func) ? cur_func->addr : invalid_addr, disasm->str(instr, 0));
959 			if (disasm->validInsn(instr)) {
960 				branch = analy_disasm->isBranch(instr);
961 				if (branch != br_nobranch) {
962 					doBranch(branch, instr, len);
963 				} else {
964 					analy_disasm->examineOpcode(instr);
965 				}
966 			} else {
967 				DPRINTF("invalid opcode @%y\n", addr);
968 //				log("invalid opcode at address %y\n", addr);
969 				if (!addr->add(len)) {
970 					delete addr;
971 					addr = new InvalidAddress();
972 				} else {
973 					newLocation(addr)->flags |= AF_FUNCTION_END;
974 					next_address_is_invalid = true;
975 				}
976 			}
977 		} while (disasm->selectNext(instr));
978 		if (next_address_is_invalid || !addr->add(len)) {
979 			gotoAddress(invalid_addr, invalid_addr);
980 			next_address_is_invalid = false;
981 		}
982 		free(instr);
983 	} while ((ops_parsed % MAX_OPS_PER_CONTINUE) !=0);
984 	return true;
985 }
986 
987 /*
988  *
989  */
continueAnalysisAt(Address * Addr)990 void Analyser::continueAnalysisAt(Address *Addr)
991 {
992 	if (!validAddress(Addr, sccode)) return;
993 	if (queryConfig(Q_DO_ANALYSIS)) {
994 		DPRINTF("continueing analysis at %y\n", Addr);
995 		if (active || disasm) {
996 			data->setCodeAddressType(Addr, dst_function);
997 			pushAddress(Addr, Addr);
998 		}
999 		if (!active) {
1000 			if (disasm) {
1001 				Analyser::beginAnalysis();
1002 			} else {
1003 				DPRINTF("couldn't start analysis: no disasm available\n");
1004 			}
1005 		}
1006 	}
1007 }
1008 
1009 /*
1010  *	should return a new instance of an apropriate assembler
1011  */
createAssembler()1012 Assembler *Analyser::createAssembler()
1013 {
1014 	return NULL;
1015 }
1016 
1017 /*
1018  *
1019  */
dataAccess(Address * Addr,taccess access)1020 void	Analyser::dataAccess(Address *Addr, taccess access)
1021 {
1022 	if (!validAddress(Addr, scvalid)) {
1023 		char	msg[100];
1024 		global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1025 		ht_snprintf(msg, sizeof msg, "access of invalid addr %y at addr %y", Addr, addr);
1026 		log(msg);
1027 		return;
1028 	}
1029 
1030 	DPRINTF("dataaccess of %y\n", Addr);
1031 
1032 	// string test
1033 	byte buffer[1024];
1034 
1035 	if (validAddress(Addr, scinitialized)) {
1036 		uint bz = bufPtr(Addr, buffer, sizeof buffer);
1037 		if (bz > 2) {
1038 			analy_string *str = string_test(buffer, bz);
1039 			if (str) {
1040 				char string1[128], string2[128];
1041 				str->render_string(string2, sizeof string2);
1042 				ht_snprintf(string1, sizeof string1, "%s_%s", str->name(), string2);
1043 				make_valid_name(string2, string1);
1044 				if (addAddressSymbol(Addr, string2, label_data)) {
1045 					addComment(Addr, 0, "");
1046 				}
1047 				data->setArrayAddressType(Addr, dst_string, str->length());
1048 				str->done();
1049 				delete str;
1050 				return;
1051 			}
1052 		}
1053 	}
1054 
1055 	if (validCodeAddress(Addr) && access.type == acoffset) {
1056 		if (addAddressSymbol(Addr, LPRFX_OFS, label_func)) {
1057 			addComment(Addr, 0, "");
1058 		}
1059 		Location *a = getLocationByAddress(Addr);
1060 		assert(a);
1061 		// test if Addr points to code
1062 		if ((a->type.type == dt_unknown) || (a->type.type == dt_code)) {
1063 			// test if Addr points to valid code (test not yet complete)
1064 			byte buf[16];
1065 			int bz = bufPtr(Addr, buf, sizeof(buf));
1066 			OPCODE *instr = disasm->decode(buf, MIN(bz, max_opcode_length), mapAddr(Addr));
1067 			if (disasm->validInsn(instr)) {
1068 				data->setCodeAddressType(Addr, dst_cunknown);
1069 				pushAddress(Addr, Addr);
1070 			}
1071 		}
1072 	} else {
1073 		if (access.type != acoffset) {
1074 			switch (access.size) {
1075 				case 1: data->setIntAddressType(Addr, dst_ibyte, 1); break;
1076 				case 2: data->setIntAddressType(Addr, dst_iword, 2); break;
1077 				case 4: data->setIntAddressType(Addr, dst_idword, 4); break;
1078 			}
1079 		}
1080 		if (validAddress(Addr, scinitialized)) {
1081 			addAddressSymbol(Addr, LPRFX_DTA, label_data);
1082 		} else {
1083 			addAddressSymbol(Addr, LPRFX_DTU, label_data);
1084 		}
1085 	}
1086 }
1087 
1088 /*
1089  *	disables address, frees misc
1090  */
deleteLocation(Address * Addr)1091 void	Analyser::deleteLocation(Address *Addr)
1092 {
1093 	Location *a = getLocationByAddress(Addr);
1094 	if (a) {
1095 		disableSymbol(a->label);
1096 		a->label = NULL;
1097 		a->flags |= AF_DELETED;
1098 		location_count--;
1099 	}
1100 }
1101 
1102 /*
1103  *	disables label of an address and unassigns address' label
1104  */
deleteSymbol(Address * Addr)1105 void Analyser::deleteSymbol(Address *Addr)
1106 {
1107 	Location *a = getLocationByAddress(Addr);
1108 	if (a) {
1109 		disableSymbol(a->label);
1110 		a->label = NULL;
1111 		symbol_count--;
1112 	}
1113 }
1114 
1115 /*
1116  *
1117  */
deleteXRef(Address * from,Address * to)1118 bool Analyser::deleteXRef(Address *from, Address *to)
1119 {
1120 	if (!validAddress(from, scvalid) || !validAddress(to, scvalid)) return false;
1121 
1122 	Location *a = getLocationByAddress(from);
1123 	if (!a) return false;
1124 	Container *x = a->xrefs;
1125 	if (!x) return false;
1126 
1127 	DPRINTF("deleted xref %y->%y\n", from, to);
1128 
1129 	AddrXRef tmp(to);
1130 	return x->delObj(&tmp);
1131 }
1132 
1133 /*
1134  *	an disabled label will be overwritten as soon as possible,
1135  *   and never be returned nor saved.
1136  *	performed this way to preserve the labeltrees structure
1137  *
1138  */
disableSymbol(Symbol * label)1139 void	Analyser::disableSymbol(Symbol *label)
1140 {
1141 	if (label) {
1142 		label->location = NULL;
1143 	}
1144 }
1145 
1146 /*
1147  *
1148  */
doBranch(branch_enum_t branch,OPCODE * opcode,int len)1149 void	Analyser::doBranch(branch_enum_t branch, OPCODE *opcode, int len)
1150 {
1151 	Address *branch_addr = analy_disasm->branchAddr(opcode, branch, true);
1152 
1153 	if (branch != br_return) {
1154 		if (!validCodeAddress(branch_addr)) {
1155 			char	msg[100];
1156 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1157 			ht_snprintf(msg, sizeof msg, "branch to invalid addr %y from addr %y", branch_addr, addr);
1158 			log(msg);
1159 		}
1160 	}
1161 /*	if (branch != brcall) {
1162 		taddr *a = new_addr(addr+len);
1163 		if (!a->comments) {
1164 			add_comment(a->addr, 0, "");
1165 		}
1166 	}*/
1167 	Address *next_addr = addr->clone();
1168 	if (!next_addr->add(len)) {
1169 		delete next_addr;
1170 		next_addr = new InvalidAddress();
1171 	}
1172 	switch (branch) {
1173 		case	br_jump:
1174 			if (next_addr->isValid())
1175 				newLocation(next_addr)->flags |= AF_FUNCTION_END;
1176 
1177 			addXRef(branch_addr, addr, xrefjump);
1178 			if (addAddressSymbol(branch_addr, LPRFX_LOC, label_loc, cur_func)) {
1179 				addComment(branch_addr, 0, "");
1180 			}
1181 //			gotoAddress(branch_addr, invalid_addr);
1182 			pushAddress(branch_addr, invalid_addr);
1183 			next_address_is_invalid = true;
1184 			break;
1185 		case	br_return:
1186 			if (next_addr->isValid())
1187 				newLocation(next_addr)->flags |= AF_FUNCTION_END;
1188 
1189 			next_address_is_invalid = true;
1190 			break;
1191 		case	br_call: {
1192 			addXRef(branch_addr, addr, xrefcall);
1193 			bool special_func = false;
1194 			const char *lprfx = LPRFX_SUB;
1195 			if (!getSymbolByAddress(branch_addr) && validCodeAddress(branch_addr)) {
1196 				// should be in code_analy
1197 				byte buf[16];
1198 				int bz = bufPtr(branch_addr, buf, sizeof(buf));
1199 				OPCODE *instr = disasm->decode(buf, MIN(bz, max_opcode_length), mapAddr(branch_addr));
1200 				branch_enum_t bt = analy_disasm->isBranch(instr);
1201 
1202 				if (bt == br_return) {
1203 					lprfx = LPRFX_STUB;
1204 				} else if (bt == br_jump) {
1205 					char buf[1024], label[1024];
1206 					Address *wrap_addr = analy_disasm->branchAddr(instr, bt, false);
1207 					if (validAddress(wrap_addr, scvalid)) {
1208 						Symbol *l = getSymbolByAddress(wrap_addr);
1209 						addComment(branch_addr, 0, "");
1210 						addComment(branch_addr, 0, ";----------------------------------------------");
1211 						global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT;
1212 						if (l && l->name) {
1213 							ht_snprintf(buf, sizeof buf, "%s %s", ";  W R A P P E R for", l->name);
1214 							ht_snprintf(label, sizeof label, "%s_%s_%y", LPRFX_WRAP, l->name, branch_addr);
1215 						} else {
1216 							ht_snprintf(buf, sizeof buf, "%s %s %y", ";  W R A P P E R for", "address", wrap_addr);
1217 							ht_snprintf(label, sizeof label, "%s_%y_%y", LPRFX_WRAP, wrap_addr, branch_addr);
1218 						}
1219 						addComment(branch_addr, 0, buf);
1220 						addComment(branch_addr, 0, ";----------------------------------------------");
1221 						addSymbol(branch_addr, label, label_func);
1222 						special_func = true;
1223 					}
1224 					delete wrap_addr;
1225 				}
1226 			}
1227 			if (!special_func && addAddressSymbol(branch_addr, lprfx, label_func)) {
1228 				addComment(branch_addr, 0, "");
1229 				addComment(branch_addr, 0, ";-----------------------");
1230 				addComment(branch_addr, 0, ";  S U B R O U T I N E");
1231 				addComment(branch_addr, 0, ";-----------------------");
1232 				if (branch_addr->compareTo(cur_func->addr) == 0) {
1233 					addComment(branch_addr, 0, ";  (recursive)");
1234 				}
1235 			}
1236 //			pushAddress(next_addr, cur_func->addr);
1237 //			gotoAddress(branch_addr, branch_addr);
1238 			pushAddress(branch_addr, branch_addr);
1239 			break;
1240 		}
1241 		case	br_jXX:
1242 			addXRef(branch_addr, addr, xrefjump);
1243 			if (addAddressSymbol(branch_addr, LPRFX_LOC, label_loc, cur_func)) {
1244 				addComment(branch_addr, 0, "");
1245 			}
1246 //			pushAddress(next_addr, cur_func->addr);
1247 //			gotoAddress(branch_addr, invalid_addr);
1248 			pushAddress(branch_addr, invalid_addr);
1249 			break;
1250 		default:{}
1251 			// stupid but neccessary
1252 	}
1253 	delete next_addr;
1254 	delete branch_addr;
1255 }
1256 
1257 /*
1258  *
1259  */
engageCodeanalyser()1260 void	Analyser::engageCodeanalyser()
1261 {
1262 	if (queryConfig(Q_ENGAGE_CODE_ANALYSER)) {
1263 		DPRINTF("starting code analyser.\n");
1264 	}
1265 }
1266 
analyserenum_addrs(Location * locs,Address * at,Location * & loc)1267 static void analyserenum_addrs(Location *locs, Address *at, Location *&loc)
1268 {
1269 	if ((at->compareTo(locs->addr) < 0) || !at->isValid()) {
1270 		loc = locs;
1271 		if (locs->left) analyserenum_addrs(locs->left, at, loc);
1272 	} else /*if (at >= locs->addr)*/ {
1273 		if (locs->right) analyserenum_addrs(locs->right, at, loc);
1274 	}
1275 }
1276 
1277 /*
1278  *
1279  */
enumLocations(Address * Addr)1280 Location *Analyser::enumLocations(Address *Addr)
1281 {
1282 	Location *result = NULL;
1283 	if (locations) analyserenum_addrs(locations, Addr, result);
1284 	while (result && (result->flags & AF_DELETED)) {
1285 		Address *a = result->addr;
1286 		result = NULL;
1287 		analyserenum_addrs(locations, a, result);
1288 	}
1289 	return result;
1290 }
1291 
analyserenum_addrs_back(Location * locs,Address * at,Location * & loc)1292 static void analyserenum_addrs_back(Location *locs, Address *at, Location *&loc)
1293 {
1294 	if (at->compareTo(locs->addr) <= 0) {
1295 		if (locs->left) analyserenum_addrs_back(locs->left, at, loc);
1296 	} else /*if (at > locs->addr)*/ {
1297 		loc = locs;
1298 		if (locs->right) analyserenum_addrs_back(locs->right, at, loc);
1299 	}
1300 }
1301 
1302 /*
1303  *
1304  */
enumLocationsReverse(Address * Addr)1305 Location *Analyser::enumLocationsReverse(Address *Addr)
1306 {
1307 	Location *result = NULL;
1308 	if (locations) analyserenum_addrs_back(locations, Addr, result);
1309 	while ((result) && (result->flags & AF_DELETED)) {
1310 		Address *a = result->addr;
1311 		result = NULL;
1312 		analyserenum_addrs_back(locations, a, result);
1313 	}
1314 	return result;
1315 }
1316 
analyserenum_labels(Symbol * labels,const char * at,Symbol * & label)1317 static void analyserenum_labels(Symbol *labels, const char *at, Symbol *&label)
1318 {
1319 	int i = strcmp(at, labels->name);
1320 	if (i < 0) {
1321 		label = labels;
1322 		if (labels->left) analyserenum_labels(labels->left, at, label);
1323 	} else /*if (i >= 0)*/ {
1324 		if (labels->right) analyserenum_labels(labels->right, at, label);
1325 	}
1326 }
1327 
1328 /*
1329  *   returns the (alphanumerically) next label to "at"
1330  *	or the first if "at" is NULL
1331  *	returns NULL if there is no preceding label
1332  *
1333  */
enumSymbolsByName(const char * at)1334 Symbol *Analyser::enumSymbolsByName(const char *at)
1335 {
1336 	Symbol *result = NULL;
1337 	if (!at) at="";
1338 	if (symbols) analyserenum_labels(symbols, at, result);
1339 
1340 	// label with !addr mustnt be returned
1341 	while ((result) && (!result->location)) {
1342 		char *name = result->name;
1343 		result = NULL;
1344 		analyserenum_labels(symbols, name, result);
1345 	}
1346 
1347 	return result;
1348 }
1349 
analyserenum_labels_back(Symbol * labels,const char * at,Symbol * & label)1350 static void analyserenum_labels_back(Symbol *labels, const char *at, Symbol *&label)
1351 {
1352 	int i = strcmp(at, labels->name);
1353 	if (i <= 0) {
1354 		if (labels->left) analyserenum_labels_back(labels->left, at, label);
1355 	} else /*if (i >= 0)*/ {
1356 		label = labels;
1357 		if (labels->right) analyserenum_labels_back(labels->right, at, label);
1358 	}
1359 }
1360 
1361 /*
1362  *
1363  */
enumSymbolsByNameReverse(const char * at)1364 Symbol *Analyser::enumSymbolsByNameReverse(const char *at)
1365 {
1366 	Symbol *result = NULL;
1367 	// FIXME:
1368 	if (!at) at="\xff\xff\xff";
1369 	if (symbols) analyserenum_labels_back(symbols, at, result);
1370 
1371 	// labels with !addr mustnt be returned
1372 	while ((result) && (!result->location)) {
1373 		char *name = result->name;
1374 		result = NULL;
1375 		analyserenum_labels_back(symbols, name, result);
1376 	}
1377 
1378 	return result;
1379 }
1380 
enumSymbols(Symbol * sym)1381 Symbol *Analyser::enumSymbols(Symbol *sym)
1382 {
1383 	if (sym) {
1384 		return enumSymbolsByName(sym->name);
1385 	} else {
1386 		return enumSymbolsByName(NULL);
1387 	}
1388 }
1389 
enumSymbolsReverse(Symbol * sym)1390 Symbol *Analyser::enumSymbolsReverse(Symbol *sym)
1391 {
1392 	if (sym) {
1393 		return enumSymbolsByNameReverse(sym->name);
1394 	} else {
1395 		return enumSymbolsByNameReverse(NULL);
1396 	}
1397 }
1398 
1399 
1400 /*
1401  *
1402  */
examineData(Address * Addr)1403 taddr_typetype Analyser::examineData(Address *Addr)
1404 {
1405 	if ((validReadAddress(Addr)) && (validAddress(Addr, scinitialized))) {
1406 		DPRINTF("examinating data @%y:\n", Addr);
1407 
1408 	} else return dt_unknown;
1409 	return dt_unknown;
1410 }
1411 
1412 /*
1413  *
1414  */
analyserfindaddr(Location * locs,Address * Addr)1415 static Location *analyserfindaddr(Location *locs, Address *Addr)
1416 {
1417 	if (locs) {
1418 		if (Addr->compareTo(locs->addr) < 0) return analyserfindaddr(locs->left, Addr);
1419 		if (Addr->compareTo(locs->addr) > 0) return analyserfindaddr(locs->right, Addr);
1420 		return (locs->flags & AF_DELETED) ? NULL : locs;
1421 	}
1422 	return NULL;
1423 }
1424 
1425 /*
1426  *
1427  */
getLocationByAddress(Address * Addr)1428 Location *Analyser::getLocationByAddress(Address *Addr)
1429 {
1430 	return analyserfindaddr(locations, Addr);
1431 }
1432 
1433 /*
1434  *   finds the address Addr belongs to (if address has size > 1)
1435  */
getLocationContextByAddress(Address * Addr)1436 Location *Analyser::getLocationContextByAddress(Address *Addr)
1437 {
1438 	Location *res = enumLocationsReverse(Addr);
1439 	if (res && res->type.type != dt_unknown) {
1440 		Address *resaddr = res->addr->clone();
1441 		resaddr->add(res->type.length);
1442 		if (resaddr->compareTo(Addr) > 0) {
1443 			delete resaddr;
1444 			return res;
1445 		}
1446 		delete resaddr;
1447 	}
1448 	return NULL;
1449 }
1450 
1451 /*
1452  *	finds the function the Addr belongs to (if possible/applicable).
1453  */
getFunctionByAddress(Address * Addr)1454 Location *Analyser::getFunctionByAddress(Address *Addr)
1455 {
1456 	Location *loc = getLocationByAddress(Addr);
1457 	if (!loc) loc = enumLocationsReverse(Addr);
1458 	while (loc && !(loc->flags & AF_FUNCTION_SET)) {
1459 		if (loc->flags & AF_FUNCTION_END) return NULL;
1460 		loc = enumLocationsReverse(loc->addr);
1461 	}
1462 	return loc ? loc->thisfunc : NULL;
1463 }
1464 
1465 /*
1466  *	searches back to the last location
1467  */
getPreviousSymbolByAddress(Address * Addr)1468 Location *Analyser::getPreviousSymbolByAddress(Address *Addr)
1469 {
1470 	Location *loc = getLocationByAddress(Addr);
1471 	if (!loc) loc = enumLocationsReverse(Addr);
1472 	while (loc && !loc->label) {
1473 		if (loc->flags & AF_FUNCTION_END) return NULL;
1474 		loc = enumLocationsReverse(loc->addr);
1475 	}
1476 	return loc ? loc : NULL;
1477 }
1478 
1479 /*
1480  *
1481  */
analyserfindlabel(Symbol * labels,const char * label)1482 static Symbol *analyserfindlabel(Symbol *labels, const char *label)
1483 {
1484 	if (labels) {
1485 		int i = strcmp(label, labels->name);
1486 		if (i < 0) return analyserfindlabel(labels->left, label);
1487 		if (i > 0) return analyserfindlabel(labels->right, label);
1488 		return labels->location ? labels : NULL;
1489 	}
1490 	return NULL;
1491 }
1492 
1493 /*
1494  *
1495  */
getSymbolByName(const char * label)1496 Symbol *Analyser::getSymbolByName(const char *label)
1497 {
1498 	return analyserfindlabel(symbols, label);
1499 }
1500 
getSymbolNameByLocation(Location * loc)1501 const char *Analyser::getSymbolNameByLocation(Location *loc)
1502 {
1503 	return loc ? (loc->label ? loc->label->name : NULL): NULL;
1504 }
1505 
1506 
1507 /**
1508  *	converts |FileOfs fileofs| to |Address|
1509  */
fileofsToAddress(FileOfs fileaddr)1510 Address *Analyser::fileofsToAddress(FileOfs fileaddr)
1511 {
1512 	// abstract / stub
1513 	return new InvalidAddress();
1514 }
1515 
1516 /**
1517  *	called once every time the analyser has nothing more to do.
1518  */
finish()1519 void	Analyser::finish()
1520 {
1521 	DPRINTF("the analyser finished (for now).\n");
1522 	cur_func = NULL;
1523 	delete addr;
1524 	addr = new InvalidAddress();
1525 	setActive(false);
1526 }
1527 
1528 /*
1529  *
1530  */
freeLocation(Location * loc)1531 void Analyser::freeLocation(Location *loc)
1532 {
1533 	if (loc) {
1534 		// label will be freed separatly
1535 		delete loc->xrefs;
1536 		freeComments(loc);
1537 		delete loc->addr;
1538 		delete loc;
1539 	}
1540 }
1541 
1542 /*
1543  *
1544  */
freeLocations(Location * addrs)1545 void	Analyser::freeLocations(Location *addrs)
1546 {
1547 	if (addrs) {
1548 		freeLocations(addrs->left);
1549 		freeLocations(addrs->right);
1550 		freeLocation(addrs);
1551 	}
1552 }
1553 
1554 /*
1555  *
1556  */
freeComments(Location * aAddr)1557 void Analyser::freeComments(Location *aAddr)
1558 {
1559 	delete aAddr->comments;
1560 	aAddr->comments = NULL;
1561 }
1562 
1563 /*
1564  *
1565  */
freeSymbol(Symbol * label)1566 void Analyser::freeSymbol(Symbol *label)
1567 {
1568 	if (label) {
1569 		free(label->name);
1570 		delete label;
1571 	}
1572 }
1573 
1574 
1575 /*
1576  *
1577  */
freeSymbols(Symbol * labels)1578 void Analyser::freeSymbols(Symbol *labels)
1579 {
1580 	if (labels) {
1581 		freeSymbols(labels->left);
1582 		freeSymbols(labels->right);
1583 		freeSymbol(labels);
1584 	}
1585 }
1586 
1587 /*
1588  *
1589  */
getComments(Address * Addr)1590 CommentList *Analyser::getComments(Address *Addr)
1591 {
1592 	Location *a = getLocationByAddress(Addr);
1593 	if (a) {
1594 		return a->comments;
1595 	}
1596 	return NULL;
1597 }
1598 
analy_addr_sym_func2(CPU_ADDR Addr,int * symstrlen,void * analy)1599 static char *analy_addr_sym_func2(CPU_ADDR Addr, int *symstrlen, void *analy)
1600 {
1601 	Address *a = ((Analyser*)analy)->createAddress();
1602 	a->getFromCPUAddress(&Addr);
1603 	Location *loc = ((Analyser*)analy)->getLocationByAddress(a);
1604 	delete a;
1605 	if (loc && loc->label) {
1606 		if (symstrlen) *symstrlen = strlen(loc->label->name);
1607 		return loc->label->name;
1608 	}
1609 	return NULL;
1610 }
1611 
1612 /*
1613  *
1614  */
getDisasmStr(Address * Addr,int & length)1615 const char *Analyser::getDisasmStr(Address *Addr, int &length)
1616 {
1617 	if (validAddress(Addr, scinitialized)) {
1618 		if (disasm) {
1619 			addr_sym_func = NULL;
1620 			byte buf[16];
1621 			int bz = bufPtr(Addr, buf, sizeof(buf));
1622 			OPCODE *o = disasm->decode(buf, MIN(bz, max_opcode_length), mapAddr(Addr));
1623 			length = disasm->getSize(o);
1624 			return disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT);
1625 		} else {
1626 			return "<no disassembler!>";
1627 		}
1628 	} else {
1629 		return "";
1630 	}
1631 }
1632 
1633 /*
1634  *
1635  */
getDisasmStrFormatted(Address * Addr)1636 const char *Analyser::getDisasmStrFormatted(Address *Addr)
1637 {
1638 	if (disasm) {
1639 		addr_sym_func_context = this;
1640 		addr_sym_func = &analy_addr_sym_func2;
1641 
1642 		byte buf[16];
1643 		int bz = bufPtr(Addr, buf, sizeof(buf));
1644 		OPCODE *o=disasm->decode(buf, MIN(bz, max_opcode_length), mapAddr(Addr));
1645 		const char *res = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT);
1646 
1647 		addr_sym_func_context = NULL;
1648 		addr_sym_func = NULL;
1649 
1650 		return res;
1651 	} else {
1652 		return "<no disassembler!>";
1653 	}
1654 }
1655 
1656 /*
1657  *
1658  */
getDisplayMode()1659 int Analyser::getDisplayMode()
1660 {
1661 	return mode;
1662 }
1663 
analysergetlocationcount(Location * addr,int * c)1664 static void analysergetlocationcount(Location *addr, int *c)
1665 {
1666 	if (addr) {
1667 		analysergetlocationcount(addr->left, c);
1668 		if (!(addr->flags & AF_DELETED)) (*c)++;
1669 		analysergetlocationcount(addr->right, c);
1670 	}
1671 }
1672 
1673 /*
1674  *
1675  */
getLocationCount() const1676 int	Analyser::getLocationCount() const
1677 {
1678 	int c=0;
1679 	analysergetlocationcount(locations, &c);
1680 	return c;
1681 }
1682 
1683 /*
1684  *
1685  */
getName(String & res)1686 String & Analyser::getName(String &res)
1687 {
1688 	return res = "generic";
1689 }
1690 
analysergetsymbolcount(Symbol * l,int * c)1691 static void analysergetsymbolcount(Symbol *l, int *c)
1692 {
1693 	if (l) {
1694 		analysergetsymbolcount(l->left, c);
1695 		if (l->location) (*c)++;
1696 		analysergetsymbolcount(l->right, c);
1697 	}
1698 }
1699 
1700 /*
1701  *
1702  */
getSymbolCount() const1703 int	Analyser::getSymbolCount() const
1704 {
1705 	int c=0;
1706 	analysergetsymbolcount(symbols, &c);
1707 	return c;
1708 }
1709 
1710 /*
1711  *
1712  */
getSegmentNameByAddress(Address * Addr)1713 const char *Analyser::getSegmentNameByAddress(Address *Addr)
1714 {
1715 	return NULL;
1716 }
1717 
1718 /*
1719  *
1720  */
getSymbolByAddress(Address * Addr)1721 Symbol *Analyser::getSymbolByAddress(Address *Addr)
1722 {
1723 	Location *a = getLocationByAddress(Addr);
1724 
1725 	return (a) ? a->label : NULL;
1726 }
1727 
1728 /*
1729  *
1730  */
getType()1731 const char *Analyser::getType()
1732 {
1733 	return "generic";
1734 }
1735 
1736 /*
1737  *
1738  */
getXRefs(Address * Addr)1739 Container *Analyser::getXRefs(Address *Addr)
1740 {
1741 	Location *a = getLocationByAddress(Addr);
1742 	if (!a) return NULL;
1743 	return a->xrefs;
1744 }
1745 
1746 /*
1747  *
1748  */
gotoAddress(Address * aAddr,Address * func)1749 bool	Analyser::gotoAddress(Address *aAddr, Address *func)
1750 {
1751 	DPRINTF("goto(%y, %y)\n", aAddr, func);
1752 	int diff;
1753 
1754 	if (first_explored->difference(diff, last_explored) && diff < 0) {
1755 		DPRINTF("explored->add(%y - %y)\n", first_explored, last_explored);
1756 		explored->add(first_explored, last_explored);
1757 	}
1758 
1759 	delete first_explored;
1760 	delete last_explored;
1761 	delete next_explored;
1762 	func = func->clone();
1763 
1764 	if (!validCodeAddress(aAddr) || explored->contains(aAddr)) {
1765 		DPRINTF("Address: %y Valid: %d Explored: %d\n", addr, validCodeAddress(addr), explored->contains(addr));
1766 		do {
1767 			delete addr;
1768 			delete func;
1769 			if (!popAddress(&addr, &func)) {
1770 				first_explored = new InvalidAddress();
1771 				last_explored = new InvalidAddress();
1772 				next_explored = new InvalidAddress();
1773 				addr = new InvalidAddress();
1774 				return false;
1775 			}
1776 
1777 			DPRINTF("pop %y   (Valid: %d  Explored: %d)\n", addr, validCodeAddress(addr), explored->contains(addr));
1778 		} while ((explored->contains(addr)) || (!validCodeAddress(addr)));
1779 	} else {
1780 		if (addr != aAddr) {
1781 			delete addr;
1782 			addr = aAddr->clone();
1783 		}
1784 	}
1785 
1786 	if (func->isValid()) {
1787 		cur_func = newLocation(func);
1788 		setLocationFunction(cur_func, cur_func);
1789 	}
1790 	delete func;
1791 	next_explored = (Address *)explored->findNext(addr);
1792 	if (!next_explored) {
1793 		next_explored = new InvalidAddress();
1794 	} else {
1795 		next_explored = next_explored->clone();
1796 	}
1797 	first_explored = addr->clone();
1798 	last_explored = addr->clone();
1799 	return true;
1800 }
1801 
1802 /*
1803  *
1804  */
initCodeAnalyser()1805 void Analyser::initCodeAnalyser()
1806 {
1807 	code = new CodeAnalyser();
1808 	code->init(this);
1809 }
1810 
1811 /*
1812  *
1813  */
initDataAnalyser()1814 void Analyser::initDataAnalyser()
1815 {
1816 	data = new DataAnalyser();
1817 	data->init(this);
1818 }
1819 
1820 /*
1821  *
1822  */
isDirty()1823 bool Analyser::isDirty()
1824 {
1825 	return dirty;
1826 }
1827 
1828 /*
1829  *
1830  */
log(const char * s)1831 void	Analyser::log(const char *s)
1832 {
1833 	// stub
1834 }
1835 
1836 /*
1837  *
1838  */
makeDirty()1839 void Analyser::makeDirty()
1840 {
1841 	dirty = true;
1842 }
1843 
1844 /*
1845  *
1846  */
mapAddr(Address * aAddr)1847 CPU_ADDR Analyser::mapAddr(Address *aAddr)
1848 {
1849 	/*
1850 	 * 	this function should map the independent address Addr to a
1851 	 * 	processor dependent
1852 	 * 	e.g.    .23423 --> 00234324    (or something like this)
1853 	 *   it is only used for relativ calls/jumps
1854 	 */
1855 	CPU_ADDR a;
1856 	aAddr->putIntoCPUAddress(&a);
1857 	return a;
1858 }
1859 
newLocation(Location * & locs,Address * aAddr)1860 Location *Analyser::newLocation(Location *&locs, Address *aAddr)
1861 {
1862 	if (locs) {
1863 		if (aAddr->compareTo(locs->addr) < 0) return newLocation(locs->left, aAddr);
1864 		if (aAddr->compareTo(locs->addr) > 0) return newLocation(locs->right, aAddr);
1865 	} else {
1866 		locs = new Location;
1867 		memset(locs, 0, sizeof *locs);
1868 		locs->addr = aAddr->clone();
1869 		location_count++;
1870 	}
1871 	locs->flags &= ~AF_DELETED;
1872 	return locs;
1873 }
1874 
1875 /*
1876  *
1877  */
newLocation(Address * Addr)1878 Location *Analyser::newLocation(Address *Addr)
1879 {
1880 /*	if (!(cur_addr_ops--)) {
1881 		optimizeLocationTree();
1882 	}*/
1883 	return newLocation(locations, Addr);
1884 }
1885 
newSymbol(Symbol * & labels,const char * label,Location * loc,labeltype type)1886 Symbol *Analyser::newSymbol(Symbol *&labels, const char *label, Location *loc, labeltype type)
1887 {
1888 	if (labels) {
1889 		int i = strcmp(label, labels->name);
1890 		if (i < 0) return newSymbol(labels->left, label, loc, type);
1891 		if (i > 0) return newSymbol(labels->right, label, loc, type);
1892 		if (!labels->location) {
1893 			labels->location = loc;
1894 			if (type != label_unknown) labels->type = type;
1895 		}
1896 	} else {
1897 		labels = new Symbol;
1898 		labels->name = ht_strdup(label);
1899 		labels->location = loc;
1900 		labels->type = type;
1901 		labels->left = NULL;
1902 		labels->right = NULL;
1903 		symbol_count++;
1904 	}
1905 	return labels;
1906 }
1907 
1908 /*
1909  *
1910  */
newSymbol(const char * label,Location * loc,labeltype type,Location * infunc)1911 Symbol *Analyser::newSymbol(const char *label, Location *loc, labeltype type, Location *infunc)
1912 {
1913 /*	if (!(cur_label_ops--)) {
1914 		optimizeSymbolTree();
1915 	}*/
1916 	Symbol *result = newSymbol(symbols, label, loc, type);
1917 	if ((result) && (result->location==loc) && (infunc)) setLocationFunction(loc, infunc);
1918 	return result;
1919 }
1920 
1921 /*
1922  * optimizes(=balances) addr tree
1923  */
optimizeLocationTree()1924 void Analyser::optimizeLocationTree()
1925 {
1926 	cur_addr_ops = location_threshold;
1927 	// implement me!
1928 }
1929 
1930 /*
1931  * see optimize_addr_tree()
1932  */
optimizeSymbolTree()1933 void Analyser::optimizeSymbolTree()
1934 {
1935 	cur_label_ops = symbol_threshold;
1936 	// implement me!
1937 }
1938 
1939 /*
1940  *
1941  */
popAddress(Address ** Addr,Address ** func)1942 bool Analyser::popAddress(Address **Addr, Address **func)
1943 {
1944 	if (!addr_queue->isEmpty()) {
1945 		AddressQueueItem *aqi = (AddressQueueItem *) addr_queue->deQueue();
1946 		*Addr = aqi->addr->clone();
1947 		*func = aqi->func->clone();
1948 		delete aqi;
1949 
1950 		DPRINTF("addr %y (from sub %y) poped\n", *Addr, *func);
1951 		return true;
1952 
1953 	} else {
1954 		DPRINTF("pop failed -> analyser obviously finished\n");
1955 		return false;
1956 	}
1957 }
1958 
1959 /*
1960  *
1961  */
pushAddress(Address * Addr,Address * func)1962 void Analyser::pushAddress(Address *Addr, Address *func)
1963 {
1964 	if (validCodeAddress(Addr)) {
1965 		if (!func->isValid()) {
1966 			if (cur_func) {
1967 				func = cur_func->addr;
1968 			}
1969 		}
1970 		DPRINTF("addr %y (from func %y) pushed\n", Addr, func);
1971 		AddressQueueItem *aqi = new AddressQueueItem(Addr, func);
1972 		addr_queue->enQueue(aqi);
1973 	}
1974 }
1975 
1976 /*
1977  *
1978  */
queryConfig(int mode)1979 int	Analyser::queryConfig(int mode)
1980 {
1981 	switch (mode) {
1982 	case Q_DO_ANALYSIS:
1983 	case Q_ENGAGE_CODE_ANALYSER:
1984 	case Q_ENGAGE_DATA_ANALYSER:
1985 		return true;
1986 	default:
1987 		return 0;
1988 	}
1989 }
1990 
saveaddrs(ObjectStream & st,Location * addr)1991 static void saveaddrs(ObjectStream &st, Location *addr)
1992 {
1993 	if (addr) {
1994 		saveaddrs(st, addr->left);
1995 
1996 		if (!(addr->flags & AF_DELETED)) {
1997 			PUTX_OBJECT(st, addr->addr, "addr");
1998 			PUTX_OBJECT(st, addr->xrefs, "xrefs");
1999 			PUTX_OBJECT(st, addr->comments, "comments");
2000 
2001 			analyser_put_addrtype(st, &addr->type);
2002 
2003 			if (addr->thisfunc) {
2004 				PUTX_OBJECT(st, addr->thisfunc->addr, "func");
2005 			} else {
2006 				Address *invalid_addr = new InvalidAddress();
2007 				PUTX_OBJECT(st, invalid_addr, "func");
2008 				delete invalid_addr;
2009 			}
2010 			PUTX_INT8X(st, addr->flags, "flags");
2011 		}
2012 
2013 		saveaddrs(st, addr->right);
2014 	}
2015 }
2016 
savelabels(ObjectStream & st,Symbol * label)2017 static void savelabels(ObjectStream &st, Symbol *label)
2018 {
2019 	if (label) {
2020 		savelabels(st, label->left);
2021 
2022 		if (label->location) {
2023 			// label isn't deleted
2024 
2025 			PUTX_OBJECT(st, label->location->addr, "addr");
2026 			PUTX_STRING(st, label->name, "name");
2027 
2028 			int a = (int)label->type;
2029 			PUTX_INTX(st, a, 1, "type");
2030 		}
2031 
2032 		savelabels(st, label->right);
2033 	}
2034 }
2035 
2036 /*
2037  *
2038  */
store(ObjectStream & st) const2039 void Analyser::store(ObjectStream &st) const
2040 {
2041 	PUT_OBJECT(st, addr);
2042 
2043 	PUT_OBJECT(st, addr_queue);
2044 	PUT_INT32D(st, ops_parsed);
2045 	PUT_BOOL(st, active);
2046 	PUT_OBJECT(st, next_explored);
2047 	PUT_OBJECT(st, first_explored);
2048 	PUT_OBJECT(st, last_explored);
2049 	PUT_INT32X(st, mode);
2050 	PUT_OBJECT(st, explored);
2051 	PUT_OBJECT(st, initialized);
2052 
2053 	st.putComment("locations");
2054 	PUTX_INT32D(st, getLocationCount(), "location_count");
2055 	saveaddrs(st, locations);
2056 
2057 	st.putComment("symbols");
2058 	PUTX_INT32D(st, getSymbolCount(), "symbol_count");
2059 	savelabels(st, symbols);
2060 
2061 	PUT_OBJECT(st, analy_disasm);
2062 	PUT_OBJECT(st, disasm);
2063 	PUT_OBJECT(st, code);
2064 	PUT_OBJECT(st, data);
2065 
2066 	PUT_INT32D(st, location_threshold);
2067 	PUT_INT32D(st, symbol_threshold);
2068 
2069 	PUT_INT32D(st, max_opcode_length);
2070 
2071 	if (cur_func) {
2072 		PUTX_OBJECT(st, cur_func->addr, "cur_func");
2073 	} else {
2074 		PUTX_OBJECT(st, NULL, "cur_func");
2075 	}
2076 
2077 	dirty = false;
2078 }
2079 
2080 /*
2081  *
2082  */
setActive(bool mode)2083 void Analyser::setActive(bool mode)
2084 {
2085 	if (mode) {
2086 		if (!active) {
2087 			active = true;
2088 			some_analyser_active++;
2089 		}
2090 	} else {
2091 		if (active) {
2092 			active = false;
2093 			some_analyser_active--;
2094 		}
2095 	}
2096 }
2097 
2098 /*
2099  *
2100  */
setDisplayMode(int enable,int disable)2101 void Analyser::setDisplayMode(int enable, int disable)
2102 {
2103 	mode &= ~disable;
2104 	mode |= enable;
2105 }
2106 
2107 /*
2108  *
2109  */
setLocationFunction(Location * a,Location * func)2110 void Analyser::setLocationFunction(Location *a, Location *func)
2111 {
2112 	if (a) {
2113 		a->thisfunc = func;
2114 		a->flags &= !AF_FUNCTION_END;
2115 		a->flags |= AF_FUNCTION_SET;
2116 	}
2117 }
2118 
2119 /*
2120  *
2121  */
setDisasm(Disassembler * d)2122 void Analyser::setDisasm(Disassembler *d)
2123 {
2124 	disasm = d;
2125 	if (disasm) {
2126 		int t;
2127 		disasm->getOpcodeMetrics(t, max_opcode_length, t, t, t);
2128 	} else {
2129 		max_opcode_length = 1;
2130 	}
2131 }
2132 
2133 /*
2134  *	sets addr_threshold. after threshold addr_tree ops the tree will
2135  *	be optimized
2136  */
setLocationTreeOptimizeThreshold(int threshold)2137 void Analyser::setLocationTreeOptimizeThreshold(int threshold)
2138 {
2139 	location_threshold = threshold;
2140 	if (cur_addr_ops > location_threshold) cur_addr_ops = location_threshold;
2141 }
2142 
2143 /*
2144  *	see set_addr_tree_optimize_threshold
2145  */
setSymbolTreeOptimizeThreshold(int threshold)2146 void Analyser::setSymbolTreeOptimizeThreshold(int threshold)
2147 {
2148 	symbol_threshold = threshold;
2149 	if (cur_label_ops > symbol_threshold) cur_label_ops = symbol_threshold;
2150 }
2151 
2152 /*
2153  *
2154  */
toggleDisplayMode(int toggle)2155 void Analyser::toggleDisplayMode(int toggle)
2156 {
2157 	mode ^= toggle;
2158 }
2159 
2160 /*
2161  *
2162  */
validCodeAddress(Address * Addr)2163 bool	Analyser::validCodeAddress(Address *Addr)
2164 {
2165 	Location *a = getLocationByAddress(Addr);
2166 	if (a) {
2167 		if ((a->type.type != dt_code) && (a->type.type != dt_unknown)) return false;
2168 	}
2169 	return validAddress(Addr, sccode);
2170 }
2171 
2172 /*
2173  *
2174  */
validReadAddress(Address * Addr)2175 bool	Analyser::validReadAddress(Address *Addr)
2176 {
2177 	return validAddress(Addr, scread);
2178 }
2179 
2180 /*
2181  *
2182  */
validWriteAddress(Address * Addr)2183 bool	Analyser::validWriteAddress(Address *Addr)
2184 {
2185 	return validAddress(Addr, scwrite);
2186 }
2187 /*
2188  *	Check if a fixup is present at (Addr + offset)
2189  */
2190 
isAddressFixedUp(Address * Addr,int offset)2191 bool 	Analyser::isAddressFixedUp(Address *Addr, int offset)
2192 {
2193 	return false;
2194 }
2195 
2196 /****************************************************************************/
2197 
AnalyDisassembler()2198 AnalyDisassembler::AnalyDisassembler()
2199 {
2200 	disasm = NULL;
2201 }
2202 
2203 /*
2204  *
2205  */
init(Analyser * A)2206 void AnalyDisassembler::init(Analyser *A)
2207 {
2208 	analy = A;
2209 	initDisasm();
2210 }
2211 
2212 /*
2213  *
2214  */
initDisasm()2215 void AnalyDisassembler::initDisasm()
2216 {
2217 	if (analy) {
2218 		analy->setDisasm(disasm);
2219 	}
2220 }
2221 
2222