1 /*
2  *	HT Editor
3  *	htanaly.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 <cstdlib>
22 #include <cstring>
23 #include <memory>
24 
25 #include "analy.h"
26 #include "analy_names.h"
27 #include "log.h"
28 #include "htanaly.h"
29 #include "htctrl.h" // FIXME: globalerror
30 #include "htdialog.h"
31 #include "htdisasm.h"
32 #include "hthist.h"
33 #include "htidle.h"
34 #include "htiobox.h"
35 #include "keyb.h"
36 #include "htmenu.h"
37 #include "htsearch.h"
38 #include "strtools.h"
39 #include "httag.h"
40 #include "httree.h"
41 #include "language.h"
42 #include "textedit.h"
43 #include "textfile.h"
44 #include "tools.h"
45 #include "snprintf.h"
46 #include "syntax.h"
47 #include "out.h"
48 #include "out_ht.h"
49 #include "out_txt.h"
50 #include "store.h"
51 
52 extern "C" {
53 #include "evalx.h"
54 }
55 
56 /* FIXME: test */
57 //#include "srt.h"
58 #include "out_html.h"
59 #include "out_sym.h"
60 
61 /*
62  *   AnalyserInformation
63  */
init(Bounds * b,ht_aviewer * a)64 void	AnalyserInformation::init(Bounds *b, ht_aviewer *a)
65 {
66 	analy = a;
67 	assert(a);
68 	ht_statictext::init(b, 0, align_left);
69 	register_idle_object(this);
70 	idle();
71 }
72 
done()73 void AnalyserInformation::done()
74 {
75 	unregister_idle_object(this);
76 	ht_statictext::done();
77 }
78 
gettext(char * buf,int maxlen)79 int AnalyserInformation::gettext(char *buf, int maxlen)
80 {
81 	return ht_snprintf(buf, maxlen,
82 		"Analyser statistics:\n"
83 		"====================\n\n"
84 		"Type: %s\nFile: %y\n"
85 		"Using disassembler: %s\n\n"
86 		"Known locations: %d\n"
87 		"Known symbols: %d\n\n",
88 		atype, &aname,
89 		adis,
90 		addrs, labels);
91 }
92 
idle()93 bool AnalyserInformation::idle()
94 {
95 	if (analy && analy->analy) {
96 		addrs = analy->analy->getLocationCount();
97 		labels = analy->analy->getSymbolCount();
98 		atype = analy->analy->getType();
99 		analy->analy->getName(aname);
100 		if (analy->analy->disasm) {
101 			adis = analy->analy->disasm->getName();
102 		} else {
103 			adis = "?";
104 		}
105 		dirtyview();
106 	}
107 	return false;
108 }
109 
110 /*
111  *   SymbolBox
112  */
113 
init(Bounds * b,Analyser * Analy)114 void SymbolBox::init(Bounds *b, Analyser *Analy)
115 {
116 	analy = Analy;
117 	ht_listbox::init(b);
118 	str = ht_malloc(1024);
119 	symbols = analy->getSymbolCount();
120 	idle_count = 1;
121 }
122 
done()123 void SymbolBox::done()
124 {
125 	free(str);
126 	ht_listbox::done();
127 }
128 
calcCount()129 int  SymbolBox::calcCount()
130 {
131 	return analy->getSymbolCount();
132 }
133 
cursorAdjust()134 int  SymbolBox::cursorAdjust()
135 {
136 	Symbol *l = ((Symbol *)getFirst());
137 	if (!l) return 0;
138 	return l->location->addr->stringSize()+10;
139 }
140 
estimateEntryPos(void * entry)141 int  SymbolBox::estimateEntryPos(void *entry)
142 {
143 	return 0;
144 }
145 
getFirst()146 void *SymbolBox::getFirst()
147 {
148 	return analy->enumSymbols(NULL);
149 }
150 
getLast()151 void *SymbolBox::getLast()
152 {
153 	return analy->enumSymbolsReverse(NULL);
154 }
155 
getNext(void * entry)156 void *SymbolBox::getNext(void *entry)
157 {
158 	if (!entry) return NULL;
159 	return analy->enumSymbols((Symbol *)entry);
160 }
161 
getPrev(void * entry)162 void *SymbolBox::getPrev(void *entry)
163 {
164 	if (!entry) return NULL;
165 	return analy->enumSymbolsReverse((Symbol *)entry);
166 }
167 
getStr(int col,void * entry)168 const char *SymbolBox::getStr(int col, void *entry)
169 {
170 	if (!entry) return NULL;
171 	Symbol *l = ((Symbol *)entry);
172 	switch (col) {
173 	case 0:
174 		global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_WHITESPACE;
175 		ht_snprintf(str, 1024, "%y", l->location->addr);
176 		break;
177 	case 1:
178 		ht_snprintf(str, 1024, "%s", label_type_short(l->type));
179 		break;
180 	case 2:
181 		ht_snprintf(str, 1024, "%s", l->name);
182 		break;
183 	}
184 	return str;
185 }
186 
idle()187 bool SymbolBox::idle()
188 {
189 	if ((idle_count % 500)==0) {
190 		update();
191 		redraw();
192 		symbols = analy->getSymbolCount();
193 		idle_count = 1;
194 		return 1;
195 	}
196 	idle_count++;
197 	return 0;
198 }
199 
numColumns()200 int SymbolBox::numColumns()
201 {
202 	return 3;
203 }
204 
quickfind(const char * s)205 void *SymbolBox::quickfind(const char *s)
206 {
207 	Symbol *tmp = analy->getSymbolByName(s);
208 	if (tmp) return tmp;
209 	tmp = analy->enumSymbolsByName(s);
210 	if (tmp) {
211 		int slen = strlen(s);
212 		int tlen = strlen(tmp->name);
213 		if (slen > tlen) return NULL;
214 		if (ht_strncmp(tmp->name, s, slen)==0) return tmp;
215 		return NULL;
216 	} else {
217 		return NULL;
218 	}
219 }
220 
221 
quickfindCompletition(const char * s)222 char *SymbolBox::quickfindCompletition(const char *s)
223 {
224 	if (analy->getSymbolByName(s)) {
225 		return ht_strdup(s);
226 	}
227 	Symbol *tmp = analy->enumSymbolsByName(s);
228 	if (!tmp) {
229 		return ht_strdup(s);
230 	}
231 	Symbol *tmp2 = analy->enumSymbols(tmp);
232 	if (!tmp2) {
233 		return ht_strdup(tmp->name);
234 	}
235 	int slen = strlen(s);
236 	if (ht_strncmp(tmp->name, tmp2->name, slen) != 0) {
237 		return ht_strdup(tmp->name);
238 	}
239 	char *res = ht_malloc(1024); // buffer bla
240 	strcpy(res, tmp->name);
241 	while (tmp2 && (ht_strncmp(tmp2->name, s, slen)==0)) {
242 //		fprintf(stdout, "while(%s, %s, %d)\n", tmp2->name, s, slen);
243 		int a = ht_strccomm(res, tmp2->name);
244 		res[a] = 0;
245 		tmp2 = analy->enumSymbols(tmp2);
246 	}
247 	return res;
248 }
249 
250 
251 /*
252  *	CLASS CallChain
253  */
init(Bounds * b,Analyser * Analy,Address * a,char * desc)254 void	CallChain::init(Bounds *b, Analyser *Analy, Address *a, char *desc)
255 {
256 	ht_treeview::init(b, desc);
257 	VIEW_DEBUG_NAME("CallChain");
258 	analy = Analy;
259 	root = createNode(a);
260 }
261 
CallChain_done(CallChainNode * n)262 void CallChain_done(CallChainNode *n)
263 {
264 	while (n) {
265 		CallChain_done(n->child);
266 		CallChainNode *temp = n->next;
267 		free(n);
268 		n = temp;
269 	}
270 }
271 
done()272 void	CallChain::done()
273 {
274 	CallChain_done(root);
275 	ht_treeview::done();
276 }
277 
adjust(void * node,bool expand)278 void	CallChain::adjust(void *node, bool expand)
279 {
280 	((CallChainNode*)node)->expanded = expand;
281 }
282 
createNode(Address * a)283 CallChainNode *CallChain::createNode(Address *a)
284 {
285 	CallChainNode *n = ht_malloc(sizeof(CallChainNode));
286 	n->next = NULL;
287 	n->prev = NULL;
288 	n->child = NULL;
289 	n->examined = false;
290 	n->xa = a->clone();
291 	n->faddr = analy->getFunctionByAddress(a);
292 	assert(n->faddr);
293 	n->fa = n->faddr->addr;
294 	n->expanded = false;
295 	return n;
296 }
297 
examineNode(CallChainNode * n)298 void CallChain::examineNode(CallChainNode *n)
299 {
300 	n->examined = true;
301 	if (has_children(n)) {
302 		Container *x_tree = n->faddr->xrefs;
303 		assert(x_tree);
304 		ObjHandle oh = x_tree->findFirst();
305 		AddrXRef *x = (AddrXRef *)x_tree->get(oh);
306 		assert(x);
307 		CallChainNode *nn = n->child = createNode(x->addr);
308 		while ((oh = x_tree->findNext(oh)) != invObjHandle) {
309 			x = (AddrXRef *)x_tree->get(oh);
310 			nn->next = createNode(x->addr);
311 			nn = nn->next;
312 		}
313 	}
314 }
315 
get_child(void * node,int i)316 void	*CallChain::get_child(void *node, int i)
317 {
318 	CallChainNode *p;
319 	if (node) {
320 		if (!((CallChainNode *)node)->examined) examineNode((CallChainNode*)node);
321 		p = ((CallChainNode *)node)->child;
322 	} else {
323 		p = root;
324 	}
325 	while (p && (--i)) p = p->next;
326 	return p;
327 }
328 
get_next_node(void * node)329 void	*CallChain::get_next_node(void *node)
330 {
331 	return ((CallChainNode*)node)->next;
332 }
333 
get_prev_node(void * node)334 void	*CallChain::get_prev_node(void *node)
335 {
336 	return ((CallChainNode*)node)->prev;
337 }
338 
get_root()339 void	*CallChain::get_root()
340 {
341 	return root;
342 }
343 
get_text(void * node)344 char *CallChain::get_text(void *node)
345 {
346 	static char stupid[1024]; // FIXME: static var
347 	CallChainNode *n = (CallChainNode*)node;
348 	int d = 0;
349 	n->xa->difference(d, n->faddr->addr);
350 	char sign = '+';
351 	if (d < 0) {
352 		d = -d;
353 		sign = '-';
354 	}
355 	global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT | ADDRESS_STRING_FORMAT_ADD_0X;
356 	ht_snprintf(stupid, sizeof stupid, "%s%c%x (%y)",
357 		n->faddr->label ? n->faddr->label->name : "unknown",
358 		sign,
359 		d,
360 		n->xa
361 	);
362 	return stupid;
363 }
364 
has_children(void * node)365 bool	CallChain::has_children(void *node)
366 {
367 	return ((CallChainNode*)node)->faddr->xrefs != NULL;
368 }
369 
is_expanded(void * node)370 bool	CallChain::is_expanded(void *node)
371 {
372 	return ((CallChainNode*)node)->expanded;
373 }
374 
select_node(void * node)375 void	CallChain::select_node(void *node)
376 {
377 }
378 
get_current_node()379 CallChainNode *CallChain::get_current_node()
380 {
381 	return (CallChainNode*)selected;
382 }
383 
384 
385 /////////////////////////////////////////////////////////////////////////////
386 
387 /*
388  *
389  */
init(Bounds * b,ht_aviewer * A,const char * Format)390 void AnalyInfoline::init(Bounds *b, ht_aviewer *A, const char *Format)
391 {
392 	ht_statictext::init(b, 0, align_left);
393 	VIEW_DEBUG_NAME("AnalyInfoline");
394 	analy = A;
395 	displayformat = ht_strdup(Format);
396 	addr = new InvalidAddress();
397 	fofs = INVALID_FILE_OFS;
398 }
399 
done()400 void AnalyInfoline::done()
401 {
402 	free(displayformat);
403 	delete addr;
404 	ht_statictext::done();
405 }
406 
gettext(char * buf,int maxlen)407 int AnalyInfoline::gettext(char *buf, int maxlen)
408 {
409 	if (maxlen <= 0) return 0;
410 	if (valid()) {
411 		const char *sec = analy->analy->getSegmentNameByAddress(addr);
412 		if (fofs != INVALID_FILE_OFS) {
413 			Location *a = analy->analy->getFunctionByAddress(addr);
414 			const char *func = analy->analy->getSymbolNameByLocation(a);
415 
416 			char *d = displayformat;
417 			char *ss = buf, *s = buf;
418 			while (*d) {
419 				if (*d == '%') {
420 					d++;
421 					switch (*d) {
422 					case ANALY_STATUS_ARG_SECTION:
423 						if (sec) ss += ht_snprintf(ss, maxlen-(ss-s), "%s", sec);
424 						break;
425 					case ANALY_STATUS_ARG_FILEOFFSET:
426 						ss += ht_snprintf(ss, maxlen-(ss-s), "%08qx", fofs);
427 						break;
428 					case ANALY_STATUS_ARG_RAW_UNASM: {
429 						int length;
430 						ss += ht_snprintf(ss, maxlen-(ss-s), "%s", analy->analy->getDisasmStr(addr, length));
431 						break;
432 					}
433 					case ANALY_STATUS_ARG_FUNCTION: {
434 						if (func) {
435 							int d = 0;
436 							addr->difference(d, a->addr);
437 							char sign = '+';
438 							if (d < 0) {
439 								d = -d;
440 								sign = '-';
441 							}
442 							ss += ht_snprintf(ss, maxlen-(ss-s), "%s%c%x", func, sign, d);
443 						}
444 						break;
445 					}
446 					case ANALY_STATUS_ARG_OFFSET:
447 						global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
448 						ss += ht_snprintf(ss, maxlen-(ss-s), "%y", addr);
449 						break;
450 					case '%':
451 						if (maxlen-(ss-s) > 1) {
452 							*ss++ = '%';
453 						}
454 						break;
455 					default:
456 						ss += ht_snprintf(ss, maxlen-(ss-s), " error in format ");
457 					}
458 				} else {
459 					if (maxlen - (ss-s) > 1) {
460 						// leave space for trailing zero
461 						*ss++ = *d;
462 					}
463 				}
464 				d++;
465 			}
466 			*ss = 0;
467 			return ss - s;
468 		} else {
469 			if (!sec) {
470 				return ht_strlcpy(buf, "[not in file]", maxlen);
471 			} else {
472 				return ht_snprintf(buf, maxlen, "<%s> [not in file]", sec);
473 			}
474 		}
475 	} else {
476 		return ht_strlcpy(buf, "<no analyser>", maxlen);
477 	}
478 }
479 
update(Address * cursor_addr,FileOfs ecursor_addr)480 void AnalyInfoline::update(Address *cursor_addr, FileOfs ecursor_addr)
481 {
482 	delete addr;
483 	if (valid()) {
484 		fofs = ecursor_addr;
485 		addr = cursor_addr->clone();
486 	} else {
487 		fofs = INVALID_FILE_OFS;
488 		addr = new InvalidAddress();
489 	}
490 	dirtyview();
491 	redraw();
492 }
493 
valid()494 bool AnalyInfoline::valid()
495 {
496 	return analy && analy->analy;
497 }
498 
499 /*
500  *
501  */
init(Bounds * b,const char * desc,int caps,File * file,ht_format_group * format_group,Analyser * Analy)502 void ht_aviewer::init(Bounds *b, const char *desc, int caps, File *file, ht_format_group *format_group, Analyser *Analy)
503 {
504 	analy = Analy;
505 	if (Analy) {
506 		analy->setDisplayMode(ANALY_SHOW_ADDRESS | ANALY_SHOW_COMMENTS
507 			| ANALY_SHOW_LABELS | ANALY_SHOW_XREFS
508 			| ANALY_TRANSLATE_SYMBOLS | ANALY_COLLAPSE_XREFS,
509 			ANALY_EDIT_BYTES);
510 	}
511 	analy_sub = NULL;
512 	ht_uformat_viewer::init(b, desc, caps, file, format_group);
513 	search_caps |= SEARCHMODE_BIN | SEARCHMODE_EVALSTR | SEARCHMODE_EXPR;
514 	infoline = NULL;
515 	idle_count = 0;
516 	last_active = true;
517 	pause = false;
518 	register_idle_object(this);
519 	one_load_hack = false;
520 }
521 
done()522 void ht_aviewer::done()
523 {
524 	unregister_idle_object(this);
525 	ht_uformat_viewer::done();
526 	if (analy) {
527 		analy->done(); // FIXME: this musnt be here
528 		delete analy;
529 	}
530 }
531 
attachInfoline(AnalyInfoline * V)532 void ht_aviewer::attachInfoline(AnalyInfoline *V)
533 {
534 	infoline = V;
535 }
536 
pos_to_offset(viewer_pos p,FileOfs * ofs)537 bool ht_aviewer::pos_to_offset(viewer_pos p, FileOfs *ofs)
538 {
539 	if (analy) {
540 		auto addr = convertViewerPosToAddress(p);
541 		if (!addr) return false;
542 		FileOfs o = analy->addressToFileofs(addr.get());
543 		if (o != INVALID_FILE_OFS) {
544 			*ofs = o;
545 			return true;
546 		}
547 	}
548 	return false;
549 }
550 
pos_to_string(viewer_pos p,String & result)551 bool ht_aviewer::pos_to_string(viewer_pos p, String &result)
552 {
553 	if (!analy) return false;
554 	auto a = convertViewerPosToAddress(p);
555 	if (!a) return false;
556 	Location *addr = analy->getLocationByAddress(a.get());
557 	if (addr && addr->label) {
558 		result = addr->label->name;
559 		return true;
560 	}
561 	addr = analy->getFunctionByAddress(a.get());
562 	if (addr && addr->label) {
563 		int d = 0;
564 		a->difference(d, addr->addr);
565 		result.assignFormat("%s+0%xh", addr->label->name, d);
566 		return true;
567 	}
568 	global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS | ADDRESS_STRING_FORMAT_ADD_H;
569 	result.assignFormat("%y", a.get());
570 	return true;
571 }
572 
convertViewerPosToAddress(const viewer_pos & p)573 std::unique_ptr<Address> ht_aviewer::convertViewerPosToAddress(const viewer_pos &p)
574 {
575 	std::unique_ptr<Address> a(analy->createAddress());
576 	a->getFromUInt64((uint64(p.u.line_id.id1) << 32) + p.u.line_id.id2);
577 	return std::move(a);
578 }
579 
convertAddressToViewerPos(Address * a,viewer_pos * p)580 bool ht_aviewer::convertAddressToViewerPos(Address *a, viewer_pos *p)
581 {
582 	if (a && a->isValid()) {
583 		clear_viewer_pos(p);
584 		p->u.sub = analy_sub;
585 		uint64 u;
586 		a->putIntoUInt64(u);
587 		p->u.line_id.id1 = u >> 32;
588 		p->u.line_id.id2 = u;
589 		p->u.line_id.id3 = 0;
590 		return true;
591 	} else {
592 		return false;
593 	}
594 }
595 
func(uint i,bool execute)596 const char *ht_aviewer::func(uint i, bool execute)
597 {
598 	switch (i) {
599 	case 8:
600 		if (execute) {
601 			sendmsg(cmd_analyser_symbols);
602 		}
603 		return "symbols";
604 	default:
605 		return ht_uformat_viewer::func(i, execute);
606 	}
607 	return NULL;
608 }
609 
aviewer_func_addr(eval_scalar * result,eval_str * str)610 static int aviewer_func_addr(eval_scalar *result, eval_str *str)
611 {
612 	ht_aviewer *aviewer = (ht_aviewer*)eval_get_context();
613 
614 	Address *addr = aviewer->analy->createAddress();
615 	int l = addr->parseString(str->value, str->len, aviewer->analy);
616 	if (l) {
617 		uint64 q;
618 		if (addr->putIntoUInt64(q)) {
619 			scalar_create_int_q(result, q);
620 			return 1;
621 		}
622 	} else {
623 		char buffer[1024];
624 		bin2str(buffer, str->value, MIN((uint)str->len, sizeof buffer));
625 		set_eval_error("invalid address '%s'", buffer);
626 	}
627 	return 0;
628 }
629 
aviewer_func_address_of(eval_scalar * result,eval_str * str)630 static int aviewer_func_address_of(eval_scalar *result, eval_str *str)
631 {
632 	ht_aviewer *aviewer = (ht_aviewer*)eval_get_context();
633 	char buffer[1024];
634 	bin2str(buffer, str->value, MIN((uint)str->len, sizeof buffer));
635 	Symbol *l;
636 	if ((l = aviewer->analy->getSymbolByName(buffer))) {
637 		uint64 q;
638 		if (l->location->addr->putIntoUInt64(q)) {
639 			scalar_create_int_q(result, q);
640 			return 1;
641 		}
642 	} else {
643 		set_eval_error("invalid label '%s'", buffer);
644 	}
645 	return 0;
646 }
647 
aviewer_func_fileofs(eval_scalar * result,eval_int * i)648 static int aviewer_func_fileofs(eval_scalar *result, eval_int *i)
649 {
650 	ht_aviewer *aviewer = (ht_aviewer*)eval_get_context();
651 	viewer_pos p;
652 	if (aviewer->offset_to_pos(i->value, &p)) {
653 		auto a = aviewer->convertViewerPosToAddress(p);
654 		uint64 q;
655 		if (a && a->putIntoUInt64(q)) {
656 			scalar_create_int_q(result, q);
657 			return 1;
658 		}
659 	}
660 	set_eval_error("invalid file offset or no corresponding address for '0%xh'", i->value);
661 	return 0;
662 }
663 
664 /*
665  *	for assembler
666  */
ht_aviewer_symbol_to_addr(void * Aviewer,const char * s,uint64 & v)667 static int ht_aviewer_symbol_to_addr(void *Aviewer, const char *s, uint64 &v)
668 {
669 	// FIXNEW
670 	ht_aviewer *aviewer = (ht_aviewer*)Aviewer;
671 	if (*s == '@') {
672 		s++;
673 		if (str2int(s, v, 10)) {
674 			viewer_pos vp;
675 			if (!aviewer->offset_to_pos(v, &vp)) {
676 				set_eval_error("invalid offset: %08qx", v);
677 				return false;
678 			}
679 			auto a = aviewer->convertViewerPosToAddress(vp);
680 			if (a->putIntoUInt64(v)) {
681 				return true;
682 			}
683 		}
684 		// invalid number after @
685 		return false;
686 	} else if (strcmp(s, "&") ==0) {
687 		auto a = aviewer->getCurrentAddress();
688 		if (a) {
689 			a->putIntoUInt64(v);
690 			return true;
691 		} else {
692 			return false;
693 		}
694 	} else {
695 		Symbol *l = aviewer->analy->getSymbolByName(s);
696 		if (l) {
697 			// Label
698 			auto a = l->location->addr;
699 			if (a->putIntoUInt64(v)) {
700 				return true;
701 			}
702 		}
703 	}
704 	return false;
705 }
706 
setdatastr(ht_view * v,const String & str)707 static void setdatastr(ht_view *v, const String &str)
708 {
709 	ht_inputfield_data id;
710 	id.textlen = str.length();
711 	id.text = str.content();
712 	v->databuf_set(&id, sizeof id);
713 }
714 
getdatastr(ht_inputfield_data * id,char * result)715 static void getdatastr(ht_inputfield_data *id, char *result)
716 {
717 	memcpy(result, id->text, id->textlen);
718 	result[id->textlen]=0;
719 }
720 
721 struct output_dialog_data {
722 	ht_inputfield_data id1;
723 	ht_listpopup_data lp;
724 	ht_inputfield_data id2;
725 	ht_inputfield_data id3;
726 };
727 
generateOutputDialog()728 void ht_aviewer::generateOutputDialog()
729 {
730 	if (!analy) return;
731 	if (analy->active) {
732 		infobox("Please wait until analyser has finished before generating output file!");
733 		if (analy->active) return;
734 	}
735 
736 	Bounds b;
737 	b.w=50;
738 	b.h=15;
739 	center_bounds(&b);
740 	ht_dialog *dialog;
741 	NEW_OBJECT(dialog, ht_dialog, &b, "generate analyser output", FS_KILLER | FS_TITLE | FS_MOVE);
742 	ht_view *v1, *v2;
743 	b.assign(2, 2, 25, 1);
744 	NEW_OBJECT(v1, ht_strinputfield, &b, 260);
745 	dialog->insert(v1);
746 	b.assign(2, 1, 25, 1);
747 	NEW_OBJECT(v2, ht_label, &b, "output ~filename:", v1);
748 	dialog->insert(v2);
749 
750 	String filename, basename, basename2, suffix;
751 	file->getFilename(filename);
752 	filename.rightSplit('/', suffix, basename2);
753 	basename2.rightSplit('.', basename, suffix);
754 	basename += ".out";
755 	setdatastr(v1, basename);
756 
757 	b.assign(29, 2, 15, 1);
758 	NEW_OBJECT(v1, ht_listpopup, &b);
759 	((ht_listpopup*)v1)->insertstring("HTML");
760 	((ht_listpopup*)v1)->insertstring("plain text");
761 	dialog->insert(v1);
762 	b.assign(29, 1, 15, 1);
763 	NEW_OBJECT(v2, ht_label, &b, "~output format:", v1);
764 	dialog->insert(v2);
765 	b.assign(2, 5, 35, 1);
766 	NEW_OBJECT(v1, ht_strinputfield, &b, 260);
767 	dialog->insert(v1);
768 	b.assign(2, 4, 35, 1);
769 	NEW_OBJECT(v2, ht_label, &b, "~start address:", v1);
770 	viewer_pos cur;
771 	if (get_current_pos(&cur)) {
772 		String str;
773 		pos_to_string(cur, str);
774 		setdatastr(v1, str);
775 	}
776 	dialog->insert(v2);
777 	b.assign(2, 8, 35, 1);
778 	NEW_OBJECT(v1, ht_strinputfield, &b, 260);
779 	dialog->insert(v1);
780 	b.assign(2, 7, 35, 1);
781 	NEW_OBJECT(v2, ht_label, &b, "~end address:", v1);
782 	dialog->insert(v2);
783 	if (get_current_pos(&cur)) {
784 		String str;
785 		pos_to_string(cur, str);
786 		str.append("+20");
787 		setdatastr(v1, str);
788 	}
789 	b.assign(13, 11, 9, 2);
790 	NEW_OBJECT(v1, ht_button, &b, "O~k", button_ok);
791 	dialog->insert(v1);
792 	b.assign(27, 11, 9, 2);
793 	NEW_OBJECT(v1, ht_button, &b, "~Cancel", button_cancel);
794 	dialog->insert(v1);
795 	while (dialog->run(false) == button_ok) {
796 		char filename[260];
797 		char start_str[1024], end_str[1024];
798 		viewer_pos start, end;
799 		output_dialog_data odd;
800 		ViewDataBuf vdb(dialog, &odd, sizeof odd);
801 		getdatastr(&odd.id1, filename);
802 		getdatastr(&odd.id2, start_str);
803 		getdatastr(&odd.id3, end_str);
804 		if (start_str[0] == 0) {
805 			convertAddressToViewerPos(analy_sub->lowestaddress, &start);
806 		} else {
807 			if (!string_to_pos(start_str, &start)) {
808 				errorbox(globalerror);
809 				continue;
810 			}
811 		}
812 		if (end_str[0] == 0) {
813 			convertAddressToViewerPos(analy_sub->highestaddress, &end);
814 		} else {
815 			if (!string_to_pos(end_str, &end)) {
816 				errorbox(globalerror);
817 				continue;
818 			}
819 		}
820 		auto start_addr = convertViewerPosToAddress(start);
821 		auto end_addr = convertViewerPosToAddress(end);
822 		if (!start_addr || !end_addr) {
823 			errorbox("invalid address");
824 			continue;
825 		}
826 
827 		try {
828 			String name(filename);
829 			LocalFile s(name, IOAM_WRITE, FOM_CREATE);
830 			AnalyserOutput *out = NULL;
831 			switch (odd.lp.cursor_pos) {
832 			case 0:
833 				out = new AnalyserHTMLOutput();
834 				((AnalyserHTMLOutput*)out)->init(analy, &s);
835 				break;
836 			case 1:
837 				out = new AnalyserTxtOutput();
838 				((AnalyserTxtOutput*)out)->init(analy, &s);
839 				break;
840 			}
841 			out->generateFile(start_addr.get(), end_addr.get());
842 			out->done();
843 			delete out;
844 		} catch (const IOException &e) {
845 			infobox("couldnt create file '%y': %y.", &filename, &e);
846 			continue;
847 		}
848 		break;
849 	}
850 	dialog->done();
851 	delete dialog;
852 }
853 
canCreateAddress(Address * addr,bool error_msg)854 bool ht_aviewer::canCreateAddress(Address *addr, bool error_msg)
855 {
856 	Location *ctx = analy->getLocationContextByAddress(addr);
857 	if (ctx && ctx->addr->compareTo(addr) != 0) {
858 		if (error_msg) {
859 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
860 			errorbox("Can't create new symbol: Address %y belongs to %y (%s)", addr, ctx->addr, ctx->label ? ctx->label->name : "unnamed");
861 		}
862 		return false;
863 	}
864 	return true;
865 }
866 
dataIntDialog(taddr_int_subtype subtype,int length)867 void ht_aviewer::dataIntDialog(taddr_int_subtype subtype, int length)
868 {
869 	if (!analy) return;
870 	auto current_address = getCurrentAddress();
871 	if (current_address && canCreateAddress(current_address.get(), true)) {
872 		if (analy->validAddress(current_address.get(), scinitialized)) {
873 			analy->data->setIntAddressType(current_address.get(), subtype, length);
874 		}
875 	}
876 }
877 
dataStringDialog()878 void ht_aviewer::dataStringDialog()
879 {
880 	if (!analy) return;
881 	auto current_address = getCurrentAddress();
882 	if (!current_address || !canCreateAddress(current_address.get(), true)) {
883 		return;
884 	}
885 /*
886 	Bounds b;
887 	b.w=50;
888 	b.h=15;
889 	center_bounds(&b);
890 	ht_dialog *dialog;
891 	NEW_OBJECT(dialog, ht_dialog, &b, "interprete data as string", FS_KILLER | FS_TITLE | FS_MOVE);
892 
893 	while (dialog->run(false)==button_ok) {
894 	}
895 	dialog->done();
896 	delete dialog;*/
897 
898 	if (analy->validAddress(current_address.get(), scinitialized)) {
899 		byte buffer[1024];
900 		Location *a = analy->enumLocations(current_address.get());
901 		int d = sizeof buffer;
902 		if (a) a->addr->difference(d, current_address.get());
903 		uint bz = analy->bufPtr(current_address.get(), buffer, MIN(sizeof buffer, (uint)d));
904 		if (bz > 2) {
905 			analy_string *str = string_test(buffer, bz);
906 			if (str) {
907 				char string1[128], string2[128];
908 				str->render_string(string2, sizeof string2);
909 				ht_snprintf(string1, sizeof string1, "%s_%s", str->name(), string2);
910 				make_valid_name(string2, string1);
911 				if (analy->addAddressSymbol(current_address.get(), string2, label_data)) {
912 					analy->addComment(current_address.get(), 0, "");
913 				}
914 				analy->data->setArrayAddressType(current_address.get(), dst_string, str->length());
915 				str->done();
916 				delete str;
917 			}
918 		}
919 	}
920 }
921 
922 struct export_dialog_data {
923 	ht_inputfield_data id1;
924 	ht_listpopup_data lp;
925 };
926 
exportFileDialog()927 void ht_aviewer::exportFileDialog()
928 {
929 	if (!analy) return;
930 	if (analy->active) {
931 		infobox("Please wait until analyser has finished before exporting file!");
932 		if (analy->active) return;
933 	}
934 
935 	Bounds b;
936 	b.w=50;
937 	b.h=12;
938 	center_bounds(&b);
939 	ht_dialog *dialog;
940 	NEW_OBJECT(dialog, ht_dialog, &b, "export analyser information", FS_KILLER | FS_TITLE | FS_MOVE);
941 	ht_view *v1, *v2;
942 	b.assign(2, 2, 35, 1);
943 	NEW_OBJECT(v1, ht_strinputfield, &b, 260);
944 	dialog->insert(v1);
945 	b.assign(2, 1, 35, 1);
946 	NEW_OBJECT(v2, ht_label, &b, "output ~filename:", v1);
947 	dialog->insert(v2);
948 
949 	String filename, basename, suffix;
950 	file->getFilename(filename);
951 	filename.rightSplit('.', basename, suffix);
952 	basename += ".exp";
953 	setdatastr(v1, basename);
954 
955 	b.assign(2, 5, 25, 1);
956 	NEW_OBJECT(v1, ht_listpopup, &b);
957 	((ht_listpopup*)v1)->insertstring(".sym symbol file");
958 	dialog->insert(v1);
959 	b.assign(2, 4, 25, 1);
960 	NEW_OBJECT(v2, ht_label, &b, "~export format:", v1);
961 	dialog->insert(v2);
962 
963 	b.assign(13, 8, 9, 2);
964 	NEW_OBJECT(v1, ht_button, &b, "O~k", button_ok);
965 	dialog->insert(v1);
966 	b.assign(27, 8, 9, 2);
967 	NEW_OBJECT(v1, ht_button, &b, "~Cancel", button_cancel);
968 	dialog->insert(v1);
969 	while (dialog->run(false) == button_ok) {
970 		char filename[260];
971 		export_dialog_data edd;
972 		ViewDataBuf vdb(dialog, &edd, sizeof edd);
973 		getdatastr(&edd.id1, filename);
974 
975 		String name(filename);
976 		LocalFile s(name, IOAM_WRITE, FOM_CREATE);
977 		try {
978 			switch (edd.lp.cursor_pos) {
979 			case 0:
980 				export_to_sym(analy, &s);
981 				break;
982 			}
983 		} catch (const IOException &) {
984 			infobox("couldnt create file '%s'.", filename);
985 			continue;
986 		}
987 		break;
988 	}
989 	dialog->done();
990 	delete dialog;
991 }
992 
getCurrentAddress()993 std::unique_ptr<Address> ht_aviewer::getCurrentAddress()
994 {
995 	viewer_pos vp;
996 	if (!get_current_pos(&vp)) return nullptr;
997 	return convertViewerPosToAddress(vp);
998 }
999 
get_current_offset(FileOfs * ofs)1000 bool ht_aviewer::get_current_offset(FileOfs *ofs)
1001 {
1002 	if (ht_uformat_viewer::get_current_offset(ofs)) {
1003 		return true;
1004 	} else {
1005 		auto a = getCurrentAddress();
1006 		if (!a) return false;
1007 		*ofs = analy->addressToFileofs(a.get());
1008 		return *ofs != INVALID_FILE_OFS;
1009 	}
1010 }
1011 
get_hscrollbar_pos(int * pstart,int * psize)1012 bool ht_aviewer::get_hscrollbar_pos(int *pstart, int *psize)
1013 {
1014 	if (analy_sub) {
1015 		// FIXNEW
1016 /*		if (analy_sub->highestaddress->difference(s, analy_sub->lowestaddress) && s) {
1017 			int z=MIN(size.h*16, (int)(top.line_id.id1-analy_sub->lowestaddress));
1018 			return scrollbar_pos(top.line_id.id1-analy_sub->lowestaddress, z, s, pstart, psize);
1019 		}*/
1020 	}
1021 	return false;
1022 }
1023 
getminbounds(int * width,int * height)1024 void ht_aviewer::getminbounds(int *width, int *height)
1025 {
1026 	*width = 25;
1027 	*height = 4;
1028 }
1029 
get_pindicator_str(char * buf,int max_len)1030 int ht_aviewer::get_pindicator_str(char *buf, int max_len)
1031 {
1032 	if (analy) {
1033 		auto addr = getCurrentAddress();
1034 		if (addr) {
1035 			FileOfs o;
1036 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT;
1037 			if (get_current_offset(&o)) {
1038 				return ht_snprintf(buf, max_len, " %y/@%08qx%s ", addr.get(), o, (analy->isDirty())?" dirty":"");
1039 			} else {
1040 				return ht_snprintf(buf, max_len, " %y%s ", addr.get(), (analy->isDirty())?" dirty":"");
1041 			}
1042 		}
1043 	}
1044 	return ht_snprintf(buf, max_len, " ? ");
1045 }
1046 
gotoAddress(Address * a,ht_view * source_object)1047 bool ht_aviewer::gotoAddress(Address *a, ht_view *source_object)
1048 {
1049 	viewer_pos p;
1050 	if (analy) {
1051 		if (!analy->validAddress(a, scvalid)) return false;
1052 	}
1053 	// FIXME: insert a->compare(hi, low address) here
1054 	if (convertAddressToViewerPos(a, &p)) {
1055 		return goto_pos(p, source_object);
1056 	}
1057 	return false;
1058 }
1059 
handlemsg(htmsg * msg)1060 void ht_aviewer::handlemsg(htmsg *msg)
1061 {
1062 	switch (msg->msg) {
1063 	case msg_contextmenuquery: {
1064 		ht_static_context_menu *m = new ht_static_context_menu();
1065 		m->init("~Analyser");
1066 		m->insert_entry("~Assemble...", "Ctrl-A", cmd_analyser_call_assembler, K_Control_A, 1);
1067 		m->insert_separator();
1068 		ht_static_context_menu *sub=new ht_static_context_menu();
1069 		sub->init("~Control");
1070 		sub->insert_entry("~Information...", NULL, cmd_analyser_info, 0, 1);
1071 		sub->insert_separator();
1072 		sub->insert_entry("~Save state", NULL, cmd_analyser_save, 0, 1);
1073 		sub->insert_entry("~Export to file...", "Ctrl-O", cmd_analyser_generate_output, K_Control_O, 1);
1074 		sub->insert_separator();
1075 		sub->insert_entry("~Continue at address", "c", cmd_analyser_continue, 0, 1);
1076 		sub->insert_entry("~Pause / resume", "p", cmd_analyser_pause_resume, 0, 1);
1077 		m->insert_submenu(sub);
1078 		sub=new ht_static_context_menu();
1079 		sub->init("~Jump");
1080 		sub->insert_entry("~Symbol list", "F8", cmd_analyser_symbols, 0, 1);
1081 		sub->insert_entry("~Function start", "Ctrl-F", cmd_analyser_this_function, K_Control_F, 1);
1082 		sub->insert_entry("Prev ~label", "Ctrl-L", cmd_analyser_previous_label, K_Control_L, 1);
1083 		sub->insert_entry("Follow ~ptr", "f", cmd_analyser_follow, 0, 1);
1084 		m->insert_submenu(sub);
1085 		sub=new ht_static_context_menu();
1086 		sub->init("~Location");
1087 		sub->insert_entry("~Name address (label)...", "n", cmd_analyser_name_addr, 0, 1);
1088 		sub->insert_entry("Edit co~mments", "#", cmd_analyser_comments, 0, 1);
1089 		sub->insert_entry("Show ~xrefs", "x", cmd_analyser_xrefs, 0, 1);
1090 		sub->insert_entry("~Delete location", "Del", cmd_analyser_del_addr_bindings, 0, 1);
1091 		sub->insert_entry("~Callchain", "Ctrl-T", cmd_analyser_call_chain, K_Control_T, 1);
1092 		m->insert_submenu(sub);
1093 		sub=new ht_static_context_menu();
1094 		sub->init("~Data");
1095 		sub->insert_entry("Data ~string", "s", cmd_analyser_data_string, 0, 1);
1096 		sub->insert_entry("Data ~word 32", "i", cmd_analyser_data_int, 0, 1);
1097 		sub->insert_entry("Data ~halfword 16", "h", cmd_analyser_data_half, 0, 1);
1098 		sub->insert_entry("Data ~byte 8", "b", cmd_analyser_data_byte, 0, 1);
1099 		m->insert_submenu(sub);
1100 //		m->insert_separator();
1101 //		m->insert_entry("Symbol reg trace (exp!)", "Alt-Q", cmd_analyser_srt, K_Meta_Q, 1);
1102 
1103 		msg->msg = msg_retval;
1104 		msg->data1.ptr = m;
1105 		return;
1106 	}
1107 	case msg_keypressed:
1108 		switch (msg->data1.integer) {
1109 		case K_Control_L:
1110 			sendmsg(cmd_analyser_previous_label);
1111 			clearmsg(msg);
1112 			return;
1113 		case K_Control_F:
1114 			sendmsg(cmd_analyser_this_function);
1115 			clearmsg(msg);
1116 			return;
1117 		case 'c':
1118 			if (cursor_tag_class == tag_class_sel) {
1119 				sendmsg(cmd_analyser_continue);
1120 				clearmsg(msg);
1121 				return;
1122 			}
1123 			break;
1124 		case '#':
1125 			sendmsg(cmd_analyser_comments);
1126 			clearmsg(msg);
1127 			return;
1128 		case 'F':
1129 			if (cursor_tag_class == tag_class_sel) {
1130 				sendmsg(cmd_analyser_follow_ex);
1131 				clearmsg(msg);
1132 				return;
1133 			}
1134 			break;
1135 		case 'f':
1136 			if (cursor_tag_class == tag_class_sel) {
1137 				sendmsg(cmd_analyser_follow);
1138 				clearmsg(msg);
1139 				return;
1140 			}
1141 			break;
1142 		case 'n':
1143 			sendmsg(cmd_analyser_name_addr);
1144 			clearmsg(msg);
1145 			return;
1146 		case 'p':
1147 			sendmsg(cmd_analyser_pause_resume);
1148 			clearmsg(msg);
1149 			return;
1150 		case 'i':
1151 			if (cursor_tag_class == tag_class_sel) {
1152 				sendmsg(cmd_analyser_data_int);
1153 				clearmsg(msg);
1154 			}
1155 			return;
1156 		case 'h':
1157 			if (cursor_tag_class == tag_class_sel) {
1158 				sendmsg(cmd_analyser_data_half);
1159 				clearmsg(msg);
1160 				return;
1161 			}
1162 			break;
1163 		case 'b':
1164 			if (cursor_tag_class == tag_class_sel) {
1165 				sendmsg(cmd_analyser_data_byte);
1166 				clearmsg(msg);
1167 				return;
1168 			}
1169 			break;
1170 		case 's':
1171 			sendmsg(cmd_analyser_data_string);
1172 			clearmsg(msg);
1173 			return;
1174 		case 'x':
1175 			sendmsg(cmd_analyser_xrefs);
1176 			clearmsg(msg);
1177 			return;
1178 		case K_Control_D:
1179 		case K_Delete:
1180 			sendmsg(cmd_analyser_del_addr_bindings);
1181 			clearmsg(msg);
1182 			return;
1183 		}
1184 		break;
1185 	case cmd_analyser_call_assembler: {
1186 		if (!analy) break;
1187 		Assembler *a = analy->createAssembler();
1188 		if (!a) {
1189 			// FIXME: select assembler for list
1190 			infobox("no assembler available.");
1191 			clearmsg(msg);
1192 			return;
1193 		}
1194 		viewer_pos current_pos;
1195 		if (get_current_pos(&current_pos)) {
1196 			auto current_address = getCurrentAddress();
1197 			if (current_address) {
1198 				a->set_imm_eval_proc(ht_aviewer_symbol_to_addr, (void*)this);
1199 				int want_length;
1200 				analy->getDisasmStr(current_address.get(), want_length);
1201 				dialog_assemble(this, current_pos,
1202 					              analy->mapAddr(current_address.get()),
1203 												a, analy->disasm,
1204 												analy->getDisasmStrFormatted(current_address.get()),
1205 												want_length);
1206 			}
1207 		}
1208 		a->done();
1209 		delete a;
1210 		clearmsg(msg);
1211 		return;
1212 	}
1213 	case cmd_analyser_this_function: {
1214 		if (!analy) break;
1215 		auto c = getCurrentAddress();
1216 		if (!c) break;
1217 		Location *a = analy->getFunctionByAddress(c.get());
1218 		if (a) {
1219 			gotoAddress(a->addr, this);
1220 		} else {
1221 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1222 			errorbox("Address %y doesn't belong to a function.", c.get());
1223 		}
1224 		clearmsg(msg);
1225 		return;
1226 	}
1227 	case cmd_analyser_previous_label: {
1228 		if (!analy) break;
1229 		auto c = getCurrentAddress();
1230 		if (!c) break;
1231 		Location *a = analy->getPreviousSymbolByAddress(c.get());
1232 		if (a) {
1233 			gotoAddress(a->addr, this);
1234 		} else {
1235 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1236 			errorbox("Address %y doesn't belong to a symbol.", c.get());
1237 		}
1238 		clearmsg(msg);
1239 		return;
1240 	}
1241 	case cmd_analyser_continue: {
1242 		if (!analy) break;
1243 		auto a = getCurrentAddress();
1244 		if (!a) break;
1245 		analy->continueAnalysisAt(a.get());
1246 		analy->makeDirty();
1247 		analy_sub->output->invalidateCache();
1248 		clearmsg(msg);
1249 		return;
1250 	}
1251 	case cmd_analyser_comments: {
1252 		if (!analy) break;
1253 		auto current_address = getCurrentAddress();
1254 		if (current_address) {
1255 			showComments(current_address.get());
1256 		}
1257 		clearmsg(msg);
1258 		return;
1259 	}
1260 	case cmd_analyser_name_addr: {
1261 		if (!analy) break;
1262 		auto addr = getCurrentAddress();
1263 		if (!addr || !canCreateAddress(addr.get(), true)) {
1264 			clearmsg(msg);
1265 			return;
1266 		}
1267 		global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1268 		if (analy->validAddress(addr.get(), scvalid)) {
1269 			char n[256];
1270 			char str[1024];
1271 			Symbol *l = analy->getSymbolByAddress(addr.get());
1272 			if (l) ht_strlcpy(n, l->name, sizeof n); else n[0] = 0;
1273 			ht_snprintf(str, sizeof str, "name for address %y", addr.get());
1274 			while (inputbox(str, "~label name:", n, 255, HISTATOM_NAME_ADDR)) {
1275 				if (n[0]) {
1276 					if (valid_name(n)) {
1277 						char *n2 = ht_strdup(n);
1278 						if (!analy->assignSymbol(addr.get(), n2, (l)?l->type:label_unknown)) {
1279 							l = analy->getSymbolByName(n);
1280 							global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1281 							errorbox("Label '%s' already exists at address %y!", n, l->location->addr);
1282 							free(n2);
1283 						} else {
1284 							analy->makeDirty();
1285 							analy_sub->output->invalidateCache();
1286 							break;
1287 						}
1288 					} else {
1289 						global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1290 						if (confirmbox("'%s' is an invalid label name.\nMake valid?", n)==button_yes) {
1291 							make_valid_name(n, n);
1292 						}
1293 					}
1294 				} else {
1295 					if (l) {
1296 						// delete label if applicable
1297 						global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1298 						if (confirmbox("Really delete label '%s' at address %y?",
1299 								l->name, addr.get()) == button_yes) {
1300 							analy->deleteSymbol(addr.get());
1301 							analy->makeDirty();
1302 							analy_sub->output->invalidateCache();
1303 						}
1304 					}
1305 					break;
1306 				}
1307 			}
1308 		} else {
1309 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1310 			errorbox("Address %y is invalid!", addr.get());
1311 		}
1312 		clearmsg(msg);
1313 		return;
1314 	}
1315 	case cmd_analyser_xrefs: {
1316 		if (!analy) break;
1317 		auto a = getCurrentAddress();
1318 		if (!a) break;
1319 		showXRefs(a.get());
1320 		clearmsg(msg);
1321 		return;
1322 	}
1323 	case cmd_analyser_follow: {
1324 		if (!analy) break;
1325 		auto c = getCurrentAddress();
1326 		if (!c) break;
1327 		if (!analy->validAddress(c.get(), scinitialized)) break;
1328 		std::unique_ptr<Address> b(analy->createAddress());
1329 		uint bz = b->byteSize();
1330 		if (!bz) break;
1331 		byte buf[bz];
1332 		if (analy->bufPtr(c.get(), buf, bz) != bz) break;
1333 		b->getFromArray(buf);
1334 		if (analy->validAddress(b.get(), scvalid)) {
1335 			gotoAddress(b.get(), this);
1336 		} else {
1337 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1338 			errorbox("Follow: address %y is invalid!", b.get());
1339 		}
1340 		clearmsg(msg);
1341 		return;
1342 	}
1343 	case cmd_analyser_follow_ex:
1344 		if (!analy) break;
1345 		clearmsg(msg);
1346 		return;
1347 	case cmd_analyser_pause_resume:
1348 		if (!analy) break;
1349 		pause = !pause;
1350 		clearmsg(msg);
1351 		return;
1352 	case cmd_analyser_del_addr_bindings: {
1353 		if (!analy) break;
1354 		auto addr = getCurrentAddress();
1355 		if (addr) {
1356 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1357 			if (confirmbox("Forget about address' %y bindings?\n(name, comments, xrefs, etc.)",
1358 					addr.get()) == button_yes) {
1359 				analy->deleteLocation(addr.get());
1360 				analy->makeDirty();
1361 				analy_sub->output->invalidateCache();
1362 			}
1363 		}
1364 		clearmsg(msg);
1365 		return;
1366 	}
1367 	case cmd_analyser_generate_output:
1368 		if (!analy) break;
1369 		generateOutputDialog();
1370 		clearmsg(msg);
1371 		return;
1372 	case cmd_analyser_export_file:
1373 		if (!analy) break;
1374 		exportFileDialog();
1375 		clearmsg(msg);
1376 		return;
1377 	case cmd_analyser_data_int:
1378 		if (!analy) break;
1379 		dataIntDialog(dst_idword, 4);
1380 		analy->makeDirty();
1381 		analy_sub->output->invalidateCache();
1382 		dirtyview();
1383 		clearmsg(msg);
1384 		return;
1385 	case cmd_analyser_data_half:
1386 		if (!analy) break;
1387 		dataIntDialog(dst_iword, 2);
1388 		analy->makeDirty();
1389 		analy_sub->output->invalidateCache();
1390 		dirtyview();
1391 		clearmsg(msg);
1392 		return;
1393 	case cmd_analyser_data_byte:
1394 		if (!analy) break;
1395 		dataIntDialog(dst_ibyte, 1);
1396 		analy->makeDirty();
1397 		analy_sub->output->invalidateCache();
1398 		dirtyview();
1399 		clearmsg(msg);
1400 		return;
1401 	case cmd_analyser_data_string:
1402 		if (!analy) break;
1403 		dataStringDialog();
1404 		analy->makeDirty();
1405 		analy_sub->output->invalidateCache();
1406 		dirtyview();
1407 		clearmsg(msg);
1408 		return;
1409 	case cmd_analyser_info: {
1410 		if (!analy) break;
1411 		auto current_address = getCurrentAddress();
1412 		showInfo(current_address.get());
1413 		dirtyview();
1414 		clearmsg(msg);
1415 		return;
1416 	}
1417 	case cmd_analyser_symbols: {
1418 		auto current_address = getCurrentAddress();
1419 		if (!current_address) return;
1420 		showSymbols(current_address.get());
1421 		clearmsg(msg);
1422 		return;
1423 	}
1424 	case cmd_edit_mode:
1425 	case cmd_view_mode:
1426 		if (analy) {
1427 			if (edit()) {
1428 				analy->setDisplayMode(ANALY_EDIT_BYTES, 0);
1429 			} else {
1430 				analy->setDisplayMode(0, ANALY_EDIT_BYTES);
1431 			}
1432 		}
1433 		analy_sub->output->invalidateCache();
1434 		break;
1435 	case msg_file_changed: {
1436 		analy_sub->output->invalidateCache();
1437 		break;
1438 	}
1439 	case cmd_analyser_call_chain: {
1440 		if (!analy) break;
1441 		auto addr = getCurrentAddress();
1442 		if (addr) {
1443 			showCallChain(addr.get());
1444 		}
1445 		return;
1446 	}
1447 	/* FIXME: srt-experimental */
1448 /*	case cmd_analyser_srt: {
1449 		Address *current_addr;
1450 		if (getCurrentAddress(&current_addr)) {
1451 			test_srt(analy, current_addr);
1452 			delete current_addr;
1453 		}
1454 		clearmsg(msg);
1455 		return;
1456 	}*/
1457 	case msg_get_analyser: {
1458 		msg->msg = msg_retval;
1459 		msg->data1.ptr = analy;
1460 		return;
1461 	}
1462 	case msg_set_analyser: {
1463 		Analyser *a = (Analyser*)msg->data1.ptr;
1464 		if (analy) {
1465 			analy->done();
1466 			delete analy;
1467 		}
1468 		a->setDisplayMode(0, ANALY_EDIT_BYTES);
1469 		setAnalyser(a);
1470 		analy_sub->output->invalidateCache();
1471 		clearmsg(msg);
1472 		one_load_hack = true;
1473 		return;
1474 	}
1475 	case msg_postinit:
1476 		if (analy && !one_load_hack) {
1477 			analy->beginAnalysis();
1478 			analy_sub->output->invalidateCache();
1479 		}
1480 		return;
1481 	}
1482 
1483 	ht_uformat_viewer::handlemsg(msg);
1484 
1485 	switch (msg->msg) {
1486 	case msg_draw:
1487 		if (infoline) {
1488 			FileOfs a;
1489 			auto addr = getCurrentAddress();
1490 			if (!addr) {
1491 				addr = std::make_unique<InvalidAddress>();
1492 			}
1493 			infoline->update(addr.get(), (get_current_real_offset(&a)) ? a : INVALID_FILE_OFS);
1494 		}
1495 		break;
1496 	}
1497 }
1498 
idle()1499 bool ht_aviewer::idle()
1500 {
1501 	if (!analy) return false;
1502 	last_active = analy->active;
1503 	if (!pause) analy->continueAnalysis();
1504 	if (last_active && !analy->active) {
1505 		String name;
1506 		LOG("%y: analyser finished after %d ops.", &analy->getName(name), analy->ops_parsed);
1507 		dirtyview();
1508 		app->sendmsg(msg_draw, 0);
1509 	}
1510 	idle_count++;
1511 /*	if (idle_count % 565 == 0) {
1512 		analy_sub->output->invalidateCache();
1513 		dirtyview();
1514 		app->sendmsg(msg_draw, 0);
1515 	}*/
1516 	if (analy->active) {
1517 		if (idle_count%53==0) {
1518 			analy_sub->output->invalidateCache();
1519 			dirtyview();
1520 			app->sendmsg(msg_draw, 0);
1521 		}
1522 	}
1523 	return last_active && !pause;
1524 }
1525 
offset_to_pos(FileOfs ofs,viewer_pos * p)1526 bool ht_aviewer::offset_to_pos(FileOfs ofs, viewer_pos *p)
1527 {
1528 	if (!analy) return false;
1529 	Address *a = analy->fileofsToAddress(ofs);
1530 	bool res = convertAddressToViewerPos(a, p);
1531 	delete a;
1532 	return res;
1533 }
1534 
ref_sel(LINE_ID * id)1535 bool ht_aviewer::ref_sel(LINE_ID *id)
1536 {
1537 	if (!id->id1 && !id->id2 && !id->id3 && !id->id4) return 0;
1538 	switch (id->id4) {
1539 	case 0:
1540 		if (analy) {
1541 			Address *a = analy->createAddress();
1542 			a->getFromUInt64((uint64(id->id1) << 32) + id->id2);
1543 			bool res = gotoAddress(a, this);
1544 			delete a;
1545 			return res;
1546 		} else {
1547 			return false;
1548 		}
1549 	case 1:
1550 		if (analy) {
1551 			Address *a = analy->createAddress();
1552 			a->getFromUInt64((uint64(id->id1) << 32) + id->id2);
1553 			showXRefs(a);
1554 			delete a;
1555 		}
1556 		return false;
1557 	}
1558 	return false;
1559 }
1560 
reloadpalette()1561 void ht_aviewer::reloadpalette()
1562 {
1563 	ht_uformat_viewer::reloadpalette();
1564 	if (analy_sub) analy_sub->output->changeConfig();
1565 }
1566 
searchForXRefs(Address * Addr)1567 void ht_aviewer::searchForXRefs(Address *Addr)
1568 {
1569 	// FIXME: viewer_pos && FIXNEW
1570 	char str[100];
1571 	global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT;
1572 	ht_snprintf(str, sizeof str, "%y", Addr);
1573   ht_regex_search_request q(SC_VISUAL, SF_REGEX_CASEINSENSITIVE, str);
1574 	viewer_pos vp_start, vp_end;
1575 	convertAddressToViewerPos(analy_sub->lowestaddress, &vp_start);
1576 	convertAddressToViewerPos(analy_sub->highestaddress, &vp_end);
1577 	int oldmode = analy->getDisplayMode();
1578 	analy->setDisplayMode(0, -1);
1579 	analy_sub->output->invalidateCache();
1580 	ht_visual_search_result *r = (ht_visual_search_result *)vsearch(&q, vp_start, vp_end);
1581 	while (r) {
1582 		auto to = convertViewerPosToAddress(r->pos);
1583 		analy->addXRef(Addr, to.get(), xrefoffset);
1584 		viewer_pos na;
1585 		next_logical_pos(r->pos, &na);
1586 		delete r;
1587 		r = (ht_visual_search_result *)vsearch(&q, na, vp_end);
1588 	}
1589 	analy->setDisplayMode(oldmode, -1);
1590 	analy->makeDirty();
1591 	analy_sub->output->invalidateCache();
1592 }
1593 
showCallChain(Address * Addr)1594 void ht_aviewer::showCallChain(Address *Addr)
1595 {
1596 	Location *a = analy->getFunctionByAddress(Addr);
1597 	if (!a) return;
1598 	Bounds b;
1599 	b.w = 60;
1600 	b.h = 16;
1601 	center_bounds(&b);
1602 	char str[256];
1603 	global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1604 	ht_snprintf(str, sizeof str, "call chain of address %y", Addr);
1605 	ht_dialog *dialog = new ht_dialog();
1606 	dialog->init(&b, str, FS_KILLER | FS_TITLE | FS_MOVE);
1607 	b.assign(1, 0, 56, 10);
1608 	ht_statictext *text = new ht_statictext();
1609 	if (a->label) {
1610 		ht_snprintf(str, sizeof str, "function %s %s", a->label->name, "is referenced by ..");
1611 	} else {
1612 		ht_snprintf(str, sizeof str, "address %y %s", a->addr, "is referenced by ..");
1613 	}
1614 	text->init(&b, str, align_left);
1615 	dialog->insert(text);
1616 	b.assign(1, 1, 56, 10);
1617 	CallChain *cc;
1618 	NEW_OBJECT(cc, CallChain, &b, analy, Addr, NULL);
1619 	cc->adjust(cc->get_root(), true);
1620 	dialog->insert(cc);
1621 	b.assign(15, 12, 9, 2);
1622 	ht_button *bt;
1623 	NEW_OBJECT(bt, ht_button, &b, "O~k", button_ok);
1624 	dialog->insert(bt);
1625 	b.assign(35, 12, 9, 2);
1626 	NEW_OBJECT(bt, ht_button, &b, "~Cancel", button_cancel);
1627 	dialog->insert(bt);
1628 	int r = dialog->run(false);
1629 	if (r == button_ok) {
1630 		gotoAddress(cc->get_current_node()->xa, this);
1631 	}
1632 	dialog->done();
1633 	delete dialog;
1634 }
1635 
showComments(Address * Addr)1636 void ht_aviewer::showComments(Address *Addr)
1637 {
1638 	if (!analy) return;
1639 	if (!canCreateAddress(Addr, true)) {
1640 		return;
1641 	}
1642 	CommentList *comment = analy->getComments(Addr);
1643 
1644 	// prepare mem_file
1645 	MemoryFile *mem_file = new MemoryFile();
1646 	if (comment) {
1647 		int c1 = comment->count();
1648 		for (int i=0; i < c1; i++) {
1649 			const char *c = comment->getName(i);
1650 			int len = strlen(c);
1651 			if (len) mem_file->write(c, len);
1652 			if (i+1<c1) mem_file->write((void*)"\n", 1);
1653 		}
1654 	}
1655 
1656 /*     ht_c_syntax_lexer *lexer = new ht_c_syntax_lexer();
1657 	lexer->init();*/
1658 
1659 	// prepare textfile
1660 	ht_ltextfile text_file(mem_file, true, NULL);
1661 
1662 	// create dialog
1663 	Bounds b;
1664 	b.w = 60;
1665 	b.h = 16;
1666 	center_bounds(&b);
1667 	ht_dialog *dialog = new ht_dialog();
1668 	dialog->init(&b, "edit comments", FS_KILLER | FS_TITLE | FS_MOVE);
1669 
1670 	b.assign(1, 1, 55, 10);
1671 	ht_text_editor *text_editor = new ht_text_editor();
1672 	text_editor->init(&b, false, &text_file, NULL, TEXTEDITOPT_UNDO);
1673 	dialog->insert(text_editor);
1674 
1675 	/* FIXME: scrollbar
1676 	BOUNDS_ASSIGN(b, 56, 1, 1, 10);
1677 	*/
1678 
1679 	ht_button *b1;
1680 	b.assign(18, 12, 9, 2);
1681 	NEW_OBJECT(b1, ht_button, &b, "O~k", button_ok);
1682 	dialog->insert(b1);
1683 	b.assign(32, 12, 9, 2);
1684 	NEW_OBJECT(b1, ht_button, &b, "~Cancel", button_cancel);
1685 	dialog->insert(b1);
1686 
1687 	if (dialog->run(false) == button_ok) {
1688 		Location *a = analy->getLocationByAddress(Addr);
1689 		if (a) analy->freeComments(a);
1690 		uint c = text_file.linecount();
1691 		char buf[1024];
1692 		bool empty=false;
1693 		if (c == 1) {
1694 			uint l = 0;
1695 			text_file.getline(0, 0, buf, 1024, &l, NULL);
1696 			empty=(l==0);
1697 		}
1698 		if (!empty) {
1699 			for (uint i=0; i<c; i++) {
1700 				uint l;
1701 				if (text_file.getline(i, 0, buf, 1024, &l, NULL)) {
1702 					buf[l]=0;
1703 					analy->addComment(Addr, 0, buf);
1704 				}
1705 			}
1706 		}
1707 		analy->makeDirty();
1708 		analy_sub->output->invalidateCache();
1709 	}
1710 
1711 	dialog->done();
1712 	delete dialog;
1713 }
1714 
showInfo(Address * addr)1715 void ht_aviewer::showInfo(Address *addr)
1716 {
1717 	Bounds c, b;
1718 	app->getbounds(&c);
1719 	b.w=c.w*5/6;
1720 	b.h=c.h*5/6;
1721 	center_bounds(&b);
1722 	char str[100];
1723 	strcpy(str, "Analyser information");
1724 	ht_dialog *dialog = new ht_dialog();
1725 	dialog->init(&b, str, FS_KILLER | FS_TITLE | FS_MOVE);
1726 	b.assign(1, 0, b.w-4, 10);
1727 	AnalyserInformation *text = new AnalyserInformation();
1728 	text->init(&b, this);
1729 	dialog->insert(text);
1730 
1731 	dialog->run(false);
1732 
1733 	dialog->done();
1734 	delete dialog;
1735 }
1736 
showSymbols(Address * addr)1737 void ht_aviewer::showSymbols(Address *addr)
1738 {
1739 	if (!analy) return;
1740 
1741 	Location *loc = analy->getPreviousSymbolByAddress(addr);
1742 
1743 	Bounds b;
1744 	b.w = 60;
1745 	b.h = 15;
1746 	center_bounds(&b);
1747 	ht_dialog *dialog = new ht_dialog();
1748 	dialog->init(&b, "symbols", FS_KILLER | FS_TITLE | FS_MOVE | FS_RESIZE);
1749 	/* pull down */
1750 	b.assign(30, 0, 20, 1);
1751 /*				ht_listpopup *lp = new ht_listpopup();
1752 				lp->init(&b);
1753 				lp->insertstring("show all");
1754 				lp->insertstring("only functions");
1755 				lp->insertstring("only labels");
1756 				lp->insertstring("only offsets (code)");
1757 				lp->insertstring("only data");
1758 				dialog->insert(lp);*/
1759 	/* text */
1760 	b.assign(1, 0, 56, 1);
1761 	ht_listbox_title *text = new ht_listbox_title();
1762 	text->init(&b);
1763 	text->setText(3, "Address", "Type", "Name");
1764 	/* list */
1765 	b.assign(1, 1, 56, 12);
1766 	SymbolBox *sym = new SymbolBox();
1767 	sym->init(&b, analy);
1768 	if (loc && loc->label) {
1769 		sym->gotoItemByEntry(sym->quickfind(loc->label->name));
1770 	}
1771 	dialog->insert(sym);
1772 	dialog->insert(text);
1773 	sym->attachTitle(text);
1774 	register_idle_object(sym);
1775 	int r = dialog->run(false);
1776 	unregister_idle_object(sym);
1777 	if (r == button_ok) {
1778 		// goto selected symbol
1779 		ht_listbox_data d;
1780 		ViewDataBuf vdb(sym, &d, sizeof d);
1781 		if (d.data->cursor_ptr) gotoAddress(((Symbol *)d.data->cursor_ptr)->location->addr, this);
1782 	}
1783 	dialog->done();
1784 	delete dialog;
1785 }
1786 
showXRefs(Address * Addr)1787 void ht_aviewer::showXRefs(Address *Addr)
1788 {
1789 	if (!analy->getXRefs(Addr)) {
1790 		if (confirmbox("No xrefs for address %y!\nSearch for xrefs?", Addr) == button_yes) {
1791 			searchForXRefs(Addr);
1792 		}
1793 	}
1794 
1795 	Bounds c, b;
1796 	app->getbounds(&c);
1797 	b.w = c.w*5/6;
1798 	b.h = c.h*5/6;
1799 	center_bounds(&b);
1800 	int result;
1801 	do {
1802 		Container *x_tree = analy->getXRefs(Addr);
1803 		uint bw = b.w;
1804 		uint bh = b.h;
1805 		char str[256];
1806 		global_analyser_address_string_format = ADDRESS_STRING_FORMAT_COMPACT | ADDRESS_STRING_FORMAT_ADD_0X;
1807 		ht_snprintf(str, sizeof str, "xrefs of address %y", Addr);
1808 		ht_dialog *dialog = new ht_dialog();
1809 		dialog->init(&b, str, FS_KILLER | FS_TITLE | FS_MOVE | FS_RESIZE);
1810 		b.assign(1, 0, bw-4, 1);
1811 		ht_listbox_title *text = new ht_listbox_title();
1812 		text->init(&b);
1813 		text->setText(3, "xref to", "type", "from function");
1814 		b.y = 1;
1815 		b.h = bh-6;
1816 		ht_text_listbox *list;
1817 		NEW_OBJECT(list, ht_text_listbox, &b, 3, 2);
1818 		b.assign(2, bh-4, 26, 2);
1819 		ht_button *search_for_xrefs;
1820 		NEW_OBJECT(search_for_xrefs, ht_button, &b, "~Search for more XRefs", 666);
1821 		search_for_xrefs->growmode = MK_GM(GMH_LEFT, GMV_BOTTOM);
1822 		b.assign(29, bh-4, 11, 2);
1823 		ht_button *delete_xref;
1824 		NEW_OBJECT(delete_xref, ht_button, &b, "~Delete", 667);
1825 		delete_xref->growmode = MK_GM(GMH_LEFT, GMV_BOTTOM);
1826 		// FIXME: disable button when possible
1827 		b.assign(41, bh-4, 10, 2);
1828 		ht_button *new_xref;
1829 		NEW_OBJECT(new_xref, ht_button, &b, "~Add", 668);
1830 		new_xref->growmode = MK_GM(GMH_LEFT, GMV_BOTTOM);
1831 		char str2[1024];
1832 		int xcount=0;
1833 		if (x_tree) foreach(AddrXRef, x, *x_tree, {
1834 			xcount++;
1835 			global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_WHITESPACE;
1836 			ht_snprintf(str, sizeof str, "%y", x->addr);
1837 			Location *a = analy->getFunctionByAddress(x->addr);
1838 			const char *func = analy->getSymbolNameByLocation(a);
1839 			if (func) {
1840 				int d=0;
1841 				x->addr->difference(d, a->addr);
1842 				char sign = '+';
1843 				if (d < 0) {
1844 					d = -d;
1845 					sign = '-';
1846 				}
1847 				ht_snprintf(str2, sizeof str2, "%s%c%x", func, sign, d);
1848 			} else {
1849 				strcpy(str2, "?");
1850 			}
1851 			list->insert_str_extra(xcount, x->addr, str, xref_type(x->type), str2);
1852 		});
1853 		list->attachTitle(text);
1854 		list->update();
1855 		dialog->insert(text);
1856 		dialog->insert(list);
1857 		dialog->insert(search_for_xrefs);
1858 		dialog->insert(delete_xref);
1859 		dialog->insert(new_xref);
1860 		result = dialog->run(false);
1861 		ht_listbox_data data;
1862 		ViewDataBuf vdb(list, &data, sizeof data);
1863 		switch (result) {
1864 		case 666:
1865 			searchForXRefs(Addr);
1866 			break;
1867 		case 667:
1868 			if (xcount) {
1869 				analy->deleteXRef(Addr, (Address*)list->getExtra(data.data->cursor_ptr));
1870 				analy->makeDirty();
1871 				analy_sub->output->invalidateCache();
1872 			}
1873 			break;
1874 		case 668: {
1875 			char result[256];
1876 			ht_snprintf(str, sizeof str, "add xref from %y", Addr);
1877 			result[0] = 0;
1878 			while (inputbox(str, "to ~address: ", result, 255, HISTATOM_GOTO)) {
1879 				viewer_pos res_pos;
1880 				if (!string_to_pos(result, &res_pos)) {
1881 					errorbox(globalerror);
1882 					continue;
1883 				}
1884 				auto a = convertViewerPosToAddress(res_pos);
1885 				if (!a) {
1886 					errorbox("invalid address");
1887 					continue;
1888 				}
1889 				if (!analy->addXRef(Addr, a.get(), xrefoffset)) {
1890 					// FIXME: some error msg
1891 				}
1892 				analy->makeDirty();
1893 				analy_sub->output->invalidateCache();
1894 				break;
1895 			}
1896 			break;
1897 		}
1898 		case button_ok:
1899 			if (xcount) gotoAddress((Address*)list->getExtra(data.data->cursor_ptr), this);
1900 			break;
1901 		}
1902 		dialog->getbounds(&b);
1903 		dialog->done();
1904 		delete dialog;
1905 	} while (result >= 666 && result <= 668);
1906 }
1907 
func_handler(eval_scalar * result,char * name,eval_scalarlist * params)1908 bool ht_aviewer::func_handler(eval_scalar *result, char *name, eval_scalarlist *params)
1909 {
1910 	eval_func myfuncs[] = {
1911 		{"addressOf", (void*)&aviewer_func_address_of, {SCALAR_STR}, "return address of symbol"},
1912 		{"fileofs", (void*)&aviewer_func_fileofs, {SCALAR_INT}, "convert file offset to address"},
1913 //		{"addr", (void*)&aviewer_func_addr, {SCALAR_STR}}, "",
1914 		{NULL}
1915 	};
1916 	return std_eval_func_handler(result, name, params, myfuncs);
1917 }
1918 
symbol_handler(eval_scalar * result,char * name)1919 bool ht_aviewer::symbol_handler(eval_scalar *result, char *name)
1920 {
1921 	uint64 v;
1922 	viewer_pos vp;
1923 	if (*name == '@') {
1924 		name++;
1925 		if (parseIntStr(name, v, 10)) {
1926 			if (*name) return false;
1927 			if (!offset_to_pos(v, &vp)) {
1928 				set_eval_error("invalid offset: %08qx", v);
1929 				return false;
1930 			}
1931 			auto w = convertViewerPosToAddress(vp);
1932 			uint64 b = 0;
1933 			w->putIntoUInt64(b);
1934 			scalar_create_int_q(result, b);
1935 			return true;
1936 		}
1937 		// invalid number after @
1938 	} else {
1939 		if (strcmp(name, "$")==0) {
1940 			auto w = getCurrentAddress();
1941 			if (w) {
1942 				uint64 b = 0;
1943 				w->putIntoUInt64(b);
1944 				scalar_create_int_q(result, b);
1945 				return true;
1946 			} else {
1947 				return false;
1948 			}
1949 		}
1950 		Symbol *l = analy->getSymbolByName(name);
1951 		if (l) {
1952 			Address *w = l->location->addr;
1953 			uint64 b;
1954 			w->putIntoUInt64(b);
1955 			scalar_create_int_q(result, b);
1956 			return true;
1957 		}
1958 	}
1959 	return ht_uformat_viewer::symbol_handler(result, name);
1960 }
1961 
qword_to_pos(uint64 q,viewer_pos * pos)1962 bool ht_aviewer::qword_to_pos(uint64 q, viewer_pos *pos)
1963 {
1964 	if (!analy) return false;
1965 	Address *a=analy->createAddress();
1966 	a->getFromUInt64(q);
1967 	if (analy->validAddress(a, scvalid)) {
1968 		bool res = convertAddressToViewerPos(a, pos);
1969 		delete a;
1970 		return res;
1971 	} else {
1972 		global_analyser_address_string_format = ADDRESS_STRING_FORMAT_LEADING_ZEROS;
1973 		ht_snprintf(globalerror, GLOBAL_ERROR_SIZE, "address %y is invalid", a);
1974 	}
1975 	delete a;
1976 	return false;
1977 }
1978 
1979 /*
1980  *	CLASS ht_analy_sub
1981  */
1982 
init(File * file,ht_aviewer * A,Analyser * analyser,Address * Lowestaddress,Address * Highestaddress)1983 void ht_analy_sub::init(File *file, ht_aviewer *A, Analyser *analyser, Address *Lowestaddress, Address *Highestaddress)
1984 {
1985 	ht_sub::init(file);
1986 	aviewer = A;
1987 	analy = analyser;
1988 	output = new AnalyserHTOutput();
1989 	((AnalyserHTOutput*)output)->init(analy);
1990 	lowestaddress = Lowestaddress->clone();
1991 	highestaddress = Highestaddress->clone();
1992 }
1993 
done()1994 void ht_analy_sub::done()
1995 {
1996 	delete lowestaddress;
1997 	delete highestaddress;
1998 	output->done();
1999 	delete output;
2000 	ht_sub::done();
2001 }
2002 
closest_line_id(LINE_ID * line_id)2003 bool ht_analy_sub::closest_line_id(LINE_ID *line_id)
2004 {
2005 	if (!prev_line_id(line_id, 1)) {
2006 		if (!next_line_id(line_id, 1)) {
2007 			first_line_id(line_id);
2008 		}
2009 	}
2010 	return true;
2011 }
2012 
convert_ofs_to_id(const FileOfs offset,LINE_ID * line_id)2013 bool ht_analy_sub::convert_ofs_to_id(const FileOfs offset, LINE_ID *line_id)
2014 {
2015 	viewer_pos a;
2016 	if (!uformat_viewer->offset_to_pos(offset, &a)) return false;
2017 	*line_id = a.u.line_id;
2018 	return true;
2019 }
2020 
first_line_id(LINE_ID * line_id)2021 void	ht_analy_sub::first_line_id(LINE_ID *line_id)
2022 {
2023 	clear_line_id(line_id);
2024 	uint64 u;
2025 	lowestaddress->putIntoUInt64(u);
2026 	line_id->id1 = u >> 32;
2027 	line_id->id2 = u;
2028 }
2029 
getline(char * line,int maxlen,const LINE_ID line_id)2030 bool ht_analy_sub::getline(char *line, int maxlen, const LINE_ID line_id)
2031 {
2032 	if (!analy) return false;
2033 	Address *a = analy->createAddress();
2034 	a->getFromUInt64((uint64(line_id.id1) << 32) + line_id.id2);
2035 	bool res = output->getLineString(line, maxlen, a, (int)line_id.id3);
2036 	delete a;
2037 	return res;
2038 }
2039 
last_line_id(LINE_ID * line_id)2040 void	ht_analy_sub::last_line_id(LINE_ID *line_id)
2041 {
2042 	clear_line_id(line_id);
2043 	uint64 u;
2044 	highestaddress->putIntoUInt64(u);
2045 	line_id->id1 = u >> 32;
2046 	line_id->id2 = u;
2047 }
2048 
next_line_id(LINE_ID * line_id,int n)2049 int ht_analy_sub::next_line_id(LINE_ID *line_id, int n)
2050 {
2051 	if (!analy) return false;
2052 	Address *a = analy->createAddress();
2053 	a->getFromUInt64((uint64(line_id->id1) << 32) + line_id->id2);
2054 	int line = line_id->id3;
2055 	int res = output->nextLine(a, line, n, highestaddress);
2056 	if (res) {
2057 		line_id->id3 = line;
2058 		uint64 u;
2059 		a->putIntoUInt64(u);
2060 		line_id->id1 = u >> 32;
2061 		line_id->id2 = u;
2062 	}
2063 	delete a;
2064 	return res;
2065 }
2066 
prev_line_id(LINE_ID * line_id,int n)2067 int ht_analy_sub::prev_line_id(LINE_ID *line_id, int n)
2068 {
2069 	if (!analy) return false;
2070 	Address *a = analy->createAddress();
2071 	a->getFromUInt64((uint64(line_id->id1) << 32) + line_id->id2);
2072 	int line = line_id->id3;
2073 	int res = output->prevLine(a, line, n, lowestaddress);
2074 	if (res) {
2075 		line_id->id3 = line;
2076 		uint64 u;
2077 		a->putIntoUInt64(u);
2078 		line_id->id1 = u >> 32;
2079 		line_id->id2 = u;
2080 	}
2081 	delete a;
2082 	return res;
2083 }
2084 
search(ht_search_request * search,FileOfs start,FileOfs end)2085 ht_search_result *ht_analy_sub::search(ht_search_request *search, FileOfs start, FileOfs end)
2086 {
2087 	// FIXME: viewer pos
2088 	Address *st = NULL;
2089 	ht_search_result *r = NULL;
2090 	while (!r) {
2091 		st = (Address *)analy->initialized->findNext(st);
2092 		if (!st) break;
2093 		area_s *s = analy->initialized->getArea(st);
2094 		if (!s) break;
2095 		st = (Address *)s->end;
2096 		FileOfs fstart, fend;
2097 		FileOfs fsize;
2098 		viewer_pos vp_start, vp_end;
2099 		aviewer->convertAddressToViewerPos((Address *)s->start, &vp_start);
2100 		if (!aviewer->pos_to_offset(vp_start, &fstart)) assert(0);
2101 		Address *send = (Address*)s->end->clone();
2102 		send->add(-1);
2103 		aviewer->convertAddressToViewerPos(send, &vp_end);
2104 		delete send;
2105 		if (!aviewer->pos_to_offset(vp_end, &fend)) assert(0);
2106 		fsize = fend - fstart;
2107 		if (search->search_class == SC_PHYSICAL && search->type == ST_EXPR) {
2108 			r = linear_expr_search(search, start, end, this, uformat_viewer, fstart, fsize);
2109 		} else if (search->search_class == SC_PHYSICAL && search->type == ST_FXBIN) {
2110 			r = linear_bin_search(search, start, end, file, fstart, fsize);
2111 		}
2112 	}
2113 	return r;
2114 }
2115 
setAnalyser(Analyser * Analy)2116 void	ht_analy_sub::setAnalyser(Analyser *Analy)
2117 {
2118 	analy = Analy;
2119 	output->analy = Analy;
2120 	output->invalidateCache();
2121 }
2122