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(¤t_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(¤t_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