1 /*
2 * HT Editor
3 * out.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 "analy.h"
22 #include "analy_names.h"
23 #include "htdebug.h"
24 #include "strtools.h"
25 #include "snprintf.h"
26 #include "tools.h"
27 #include "out.h"
28
29 // FIXME: grrrrrrrrrrr
30 #include "x86dis.h"
31
32 #include <string.h>
33
34 #undef DPRINTF
35 #define DPRINTF(msg...)
36 #define DPRINTF2(msg...)
37 //#define DPRINTF(msg...) printf(##msg)
38 //#define DPRINTF2(msg...) printf(##msg)
39
compare_keys_addresses_delinear(Object * key_a,Object * key_b)40 int compare_keys_addresses_delinear(Object *key_a, Object *key_b)
41 {
42 return ((Address*)key_a)->compareDelinear((Address*)key_b);
43 }
44
45 /*
46 *
47 */
OutLine(byte * Text,int Textlen,int Bytes)48 OutLine::OutLine(byte *Text, int Textlen, int Bytes)
49 {
50 textlen = Textlen;
51 text = ht_malloc(Textlen);
52 memcpy(text, Text, textlen);
53 bytes = Bytes;
54 }
55
~OutLine()56 OutLine::~OutLine()
57 {
58 free(text);
59 }
60
61
62 /*
63 *
64 */
OutAddr(Address * aAddr,uint aTime)65 OutAddr::OutAddr(Address *aAddr, uint aTime)
66 {
67 addr = aAddr->clone();
68 updateTime(aTime);
69 lines = new Array(true);
70 size = 0;
71 bytes = 0;
72 }
73
~OutAddr()74 OutAddr::~OutAddr()
75 {
76 delete addr;
77 delete lines;
78 }
79
appendLine(OutLine * l)80 void OutAddr::appendLine(OutLine *l)
81 {
82 lines->insert(l);
83 bytes += l->bytes;
84 size += l->textlen;
85 }
86
clear()87 void OutAddr::clear()
88 {
89 lines->delAll();
90 bytes = 0;
91 size = 0;
92 }
93
getLine(int i)94 OutLine *OutAddr::getLine(int i)
95 {
96 return (OutLine*) (*lines)[i];
97 }
98
compareTo(const Object * o) const99 int OutAddr::compareTo(const Object *o) const
100 {
101 // uint oo = o->getObjectID();
102 return addr->compareTo(((OutAddr*)o)->addr);
103 }
104
updateTime(uint Time)105 void OutAddr::updateTime(uint Time)
106 {
107 time = Time;
108 }
109
110 /*
111 *
112 */
init(Analyser * Analy)113 void AnalyserOutput::init(Analyser *Analy)
114 {
115 analy = Analy;
116 addr = new InvalidAddress();
117 cur_addr = NULL;
118 cur_out_addr = NULL;
119 out_addrs = new AVLTree(true);
120 bytes_addr = 0;
121 bytes_line = 0;
122 size = 0;
123 current_time = 0;
124 work_buffer_start = ht_malloc(WORKBUF_LEN);
125 work_buffer = work_buffer_start;
126 work_buffer_end = work_buffer_start + WORKBUF_LEN - 1;
127 *work_buffer_end = 0;
128 temp_buffer = ht_malloc(WORKBUF_LEN);
129 dis_style = DIS_STYLE_HIGHLIGHT+DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE+X86DIS_STYLE_OPTIMIZE_ADDR;
130 changeConfig();
131 }
132
done()133 void AnalyserOutput::done()
134 {
135 delete out_addrs;
136 delete addr;
137 free(work_buffer_start);
138 free(temp_buffer);
139 }
140
beginAddr()141 void AnalyserOutput::beginAddr()
142 {
143 bytes_addr = 0;
144 line = 0;
145 }
146
beginLine()147 void AnalyserOutput::beginLine()
148 {
149 work_buffer = work_buffer_start;
150 bytes_line = 0;
151 }
152
changeConfig()153 void AnalyserOutput::changeConfig()
154 {
155 }
156
elementLength(const char * s)157 int AnalyserOutput::elementLength(const char *s)
158 {
159 return strlen(s);
160 }
161
endAddr()162 void AnalyserOutput::endAddr()
163 {
164 }
165
endLine()166 void AnalyserOutput::endLine()
167 {
168 cur_out_addr->appendLine(new OutLine(work_buffer_start, (work_buffer-work_buffer_start), bytes_line));
169 bytes_addr += bytes_line;
170 line++;
171 }
172
footer()173 void AnalyserOutput::footer()
174 {
175 // STUB
176 }
177
analyser_output_addr_sym_func(CPU_ADDR Addr,int * symstrlen,void * context)178 static char *analyser_output_addr_sym_func(CPU_ADDR Addr, int *symstrlen, void *context)
179 {
180 AnalyserOutput *output = (AnalyserOutput *) context;
181 char *buf;
182 Address *addr = output->analy->createAddress();
183 /* if (Addr.addr32.offset == 0xaea) {
184 int as=0;
185 }*/
186 addr->getFromCPUAddress(&Addr);
187 Location *loc = output->analy->getLocationByAddress(addr);
188
189 if (loc && loc->label) {
190 buf = output->link(loc->label->name, addr);
191 if (symstrlen) *symstrlen = output->elementLength(buf);
192 delete addr;
193 return buf;
194 } else {
195 if (output->analy->validAddress(addr, scvalid)) {
196 char m[90];
197 addr->stringify(m, sizeof m, ADDRESS_STRING_FORMAT_COMPACT | ADDRESS_STRING_FORMAT_ADD_H);
198 buf = output->link(m, addr);
199 if (symstrlen) *symstrlen = output->elementLength(buf);
200 delete addr;
201 return buf;
202 }
203 }
204 delete addr;
205 return NULL;
206 }
207
generateAddr(Address * Addr,OutAddr * oa)208 void AnalyserOutput::generateAddr(Address *Addr, OutAddr *oa)
209 {
210 #define LABELINDENT 32
211 #define MAX_XREF_COLS 3
212 #define MAX_XREF_LINES 7
213
214 #if 0
215 char tbuf[1024];
216 Addr->stringify(tbuf, sizeof tbuf, 0);
217 printf("generate_addr(%s, ", tbuf);
218 char tbuf2[1024];
219 addr->stringify(tbuf2, sizeof tbuf2, 0);
220 printf("%s)\n", tbuf2);
221 #endif
222
223 cur_addr = analy->getLocationByAddress(addr);
224 cur_out_addr = oa;
225 cur_out_addr->clear();
226
227 beginAddr();
228
229 if (cur_addr) {
230 int xref_count = cur_addr->xrefs ? cur_addr->xrefs->count() : 0;
231 // comments
232 CommentList *c = cur_addr->comments;
233 if (c && (analy->mode & ANALY_SHOW_COMMENTS)) {
234 int c1 = c->count();
235 for (int i=0; i < c1; i++) {
236 beginLine();
237 putElement(ELEMENT_TYPE_PRE_COMMENT, c->getName(i));
238 endLine();
239 }
240 }
241 // label && xrefs
242 bool collapsed_xrefs = false;
243 if (analy->mode & ANALY_COLLAPSE_XREFS) {
244 // count xrefs
245 if (xref_count >= MAX_XREF_COLS * MAX_XREF_LINES) {
246 collapsed_xrefs = true;
247 }
248 }
249 if ((cur_addr->label && (analy->mode & ANALY_SHOW_LABELS)) || (cur_addr->xrefs && (analy->mode & ANALY_SHOW_XREFS))) {
250 beginLine();
251 // label
252 int labellength = (cur_addr->label) ? strlen(cur_addr->label->name) : 0;
253 if (labellength && (analy->mode & ANALY_SHOW_LABELS)) {
254 putElement(ELEMENT_TYPE_LABEL, cur_addr->label->name);
255 write(":");
256 labellength++;
257 }
258 // xrefs
259 if (labellength >= LABELINDENT && cur_addr->xrefs) {
260 endLine();
261 beginLine();
262 labellength = 0;
263 }
264 if (collapsed_xrefs) {
265 for (int j=labellength; j<LABELINDENT; j++) write(" ");
266 char b[32];
267 sprintf(b, "<< show xrefs (%d) >>", xref_count);
268 char *t;
269 uint64 u;
270 Addr->putIntoUInt64(u);
271 t = externalLink(b, u >> 32, u, 0, 1, NULL);
272 write(t);
273 } else {
274 Container *xr = cur_addr->xrefs;
275 if (xr) {
276 int i=0;
277 ObjHandle xh = xr->findFirst();
278 while (xh != invObjHandle) {
279 if ((i % (MAX_XREF_COLS+1))!=0) {
280 AddrXRef *x = (AddrXRef *)xr->get(xh);
281 char buf3[90];
282 sprintf(buf3, " %c", xref_type_short(x->type));
283 write(buf3);
284 x->addr->stringify(buf3, sizeof buf3, ADDRESS_STRING_FORMAT_COMPACT);
285 write(link(buf3, x->addr));
286 xh = xr->findNext(xh);
287 } else {
288 if (i!=0) {
289 endLine();
290 beginLine();
291 }
292 for (int j=labellength; j<LABELINDENT; j++) write(" ");
293 labellength = 0;
294 putElement(ELEMENT_TYPE_COMMENT, ";xref");
295 }
296 i++;
297 }
298 }
299 }
300 endLine();
301 }
302 }
303
304 beginLine();
305
306 bool is_valid_ini_addr = analy->validAddress(addr, scinitialized);
307 bool is_valid_code_addr = analy->validCodeAddress(addr);
308
309 if (
310 is_valid_ini_addr
311 && (
312 (
313 cur_addr
314 && (
315 cur_addr->type.type == dt_code
316 || (
317 cur_addr->type.type == dt_unknown
318 && is_valid_code_addr
319 )
320 )
321 )
322 || (
323 !cur_addr
324 && is_valid_code_addr
325 )
326 )
327 ) {
328 // code
329 Location *next_addr = analy->enumLocations(addr);
330 int op_len;
331
332 // max. length of current opcode
333 if (next_addr) {
334 int d = 255;
335 next_addr->addr->difference(d, addr);
336 op_len = MIN(uint32(analy->max_opcode_length), uint(d));
337 } else {
338 op_len = analy->max_opcode_length;
339 }
340
341 byte buf[16];
342 int buffer_size = analy->bufPtr(addr, buf, sizeof buf);
343 if (analy->disasm && buffer_size) {
344 OPCODE *o = analy->disasm->decode(buf, MIN(buffer_size, op_len), analy->mapAddr(Addr));
345 /* inits for addr-sym transformations */
346 addr_sym_func_context = this;
347 if (analy->mode & ANALY_TRANSLATE_SYMBOLS) addr_sym_func = &analyser_output_addr_sym_func;
348
349 int complete_bytes_line = analy->disasm->getSize(o);
350 bool s = true;
351 do {
352 if (s) {
353 const char *x = analy->disasm->str(o, dis_style);
354 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, x);
355 }
356 if ((s = analy->disasm->selectNext(o))/* || complete_bytes_line*/) {
357 endLine();
358 beginLine();
359 } else {
360 if (analy->mode & ANALY_EDIT_BYTES) {
361 want_bytes_line = MIN(complete_bytes_line, 16);
362 } else {
363 want_bytes_line = complete_bytes_line;
364 }
365 bytes_line += want_bytes_line;
366 complete_bytes_line -= want_bytes_line;
367 }
368 } while (s || complete_bytes_line);
369
370 /* deinits for addr-sym transformations */
371 addr_sym_func_context = NULL;
372 addr_sym_func = NULL;
373 } else {
374 if (buffer_size >= 1) {
375 char buff[20];
376 sprintf(buff, "db \\@n%02xh", buf[0]);
377 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buff);
378 sprintf(buff, " ; '%c'", (buf[0]<32)?' ':buf[0]);
379 putElement(ELEMENT_TYPE_COMMENT, buff);
380
381 } else {
382 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "db ??");
383 }
384 bytes_line = want_bytes_line = 1;
385 }
386
387 } else {
388 // data
389 if (analy->validAddress(addr, scvalid)) {
390 if (cur_addr && (cur_addr->type.type != dt_unknown)
391 && (cur_addr->type.type != dt_unknown_data)
392 && (cur_addr->type.type != dt_code)) {
393 switch (cur_addr->type.type) {
394 case dt_int: {
395 bytes_line = want_bytes_line = cur_addr->type.length;
396 assert(cur_addr->type.length);
397 if (analy->validAddress(addr, scinitialized)) {
398 char buf[50];
399 switch (cur_addr->type.int_subtype) {
400 case dst_iword: {
401 uint16 c;
402 analy->bufPtr(addr, (byte *)&c, 2);
403 sprintf(buf, "dw \\@n%04xh", c);
404 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
405 break;
406 }
407 case dst_idword: {
408 uint32 c;
409 analy->bufPtr(addr, (byte *)&c, 4);
410 sprintf(buf, "dd \\@n%08xh", c);
411 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
412 break;
413 }
414 case dst_iqword: {
415 uint64 c;
416 analy->bufPtr(addr, (byte *)&c, 8);
417 ht_snprintf(buf, sizeof buf, "dq \\@n%016qxh", c);
418 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
419 break;
420 }
421 case dst_ibyte:
422 default: {
423 byte c;
424 if (analy->bufPtr(addr, &c, 1)==1) {
425 sprintf(buf, "db \\@n%02xh ", c);
426 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
427 sprintf(buf, "; '%c'", (c<32)?32:c);
428 putElement(ELEMENT_TYPE_COMMENT, buf);
429 } else {
430 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "db ??");
431 }
432 }
433 }
434 } else {
435 // not initialized
436 switch (cur_addr->type.int_subtype) {
437 case dst_iword:
438 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "dw ????");
439 break;
440 case dst_idword:
441 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "dd ????????");
442 break;
443 case dst_iqword:
444 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "dq ????????????????");
445 break;
446 case dst_ibyte:
447 default:
448 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "db ??");
449 }
450 }
451 break;
452 }
453 case dt_array: {
454 if (analy->validAddress(addr, scinitialized)) {
455 switch (cur_addr->type.array_subtype) {
456 case dst_string: {
457 char buf[1024];
458 byte bufread[1024];
459 char *b;
460 int r = analy->bufPtr(addr, bufread, MIN(cur_addr->type.length, sizeof bufread));
461 strcpy(buf, "db \\@s\"");
462 b = buf + 16 + escape_special(buf+16, 100, bufread, r, "\"", false);
463 *b++ = '\"'; *b = 0;
464 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
465 bytes_line = want_bytes_line = cur_addr->type.length;
466 break;
467 }
468 default: {assert(0);}
469 }
470 } else {
471 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "db ?");
472 }
473 break;
474 }
475 default: {
476 assert(0);
477 }
478 }
479 } else {
480 // not a known address
481 bytes_line = want_bytes_line = 1;
482 byte c;
483 if (analy->validAddress(addr, scinitialized) && (analy->bufPtr(addr, &c, 1)==1)) {
484 char buf[20];
485 sprintf(buf, "db \\@n%02xh ", c);
486 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
487 sprintf(buf, "; '%c'", (c<32)?32:c);
488 putElement(ELEMENT_TYPE_COMMENT, buf);
489 } else {
490 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "db ??");
491 }
492 }
493 } else {
494 // invalid addr
495 Address *next = analy->nextValid(Addr);
496 int d;
497 if (next && next->isValid() && next->difference(d, Addr)) {
498 bytes_line += d;
499 char buf[100];
500 sprintf(buf, "db ?? * %d", d);
501 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, buf);
502 } else {
503 bytes_line = want_bytes_line = 1;
504 putElement(ELEMENT_TYPE_HIGHLIGHT_DATA_CODE, "db ??");
505 }
506 }
507 }
508
509 endLine();
510 endAddr();
511 }
512
getGenerateStream()513 Stream *AnalyserOutput::getGenerateStream()
514 {
515 return NULL;
516 }
517
generateFile(Address * from,Address * to)518 int AnalyserOutput::generateFile(Address *from, Address *to)
519 {
520 if (analy->active) return OUTPUT_GENERATE_ERR_ANALYSER_NOT_FINISHED;
521 if (!from->isValid() || !to->isValid()) return OUTPUT_GENERATE_ERR_INVAL;
522 Stream *out = getGenerateStream();
523 if (!out) return OUTPUT_GENERATE_ERR_INVAL;
524 header();
525 int line = 0;
526 int len = 0;
527 while (from->compareTo(to) <= 0) {
528 char buffer[1024];
529 if (getLineString(buffer, sizeof buffer, from, line)) {
530 // FIXME: remove strlen
531 uint wr = strlen(buffer);
532 if (out->write(buffer, wr) != wr) return OUTPUT_GENERATE_ERR_STREAM;
533
534 int tmplen;
535 if (getLineByteLength(tmplen, from, line)) {
536 len += tmplen;
537 }
538 line++;
539 } else {
540 from->add(len);
541 len = 0;
542 line = 0;
543 }
544 }
545 footer();
546 return OUTPUT_GENERATE_ERR_OK;
547 }
548
generatePage(Address * from,int lines)549 void AnalyserOutput::generatePage(Address *from, int lines)
550 {
551
552 }
553
getAddr(Address * Addr)554 OutAddr *AnalyserOutput::getAddr(Address *Addr)
555 {
556 char tbuf[1024];
557 Addr->stringify(tbuf, sizeof tbuf, 0);
558 DPRINTF("%s -- ",tbuf);
559 if (!addr->isValid() || Addr->compareTo(addr) != 0) {
560 assert(addr != Addr);
561 DPRINTF("not cached1 --");
562 delete addr;
563 addr = Addr->clone();
564 OutAddr oatmp(addr, 0);
565 OutAddr *oa = (OutAddr*)out_addrs->get(out_addrs->find(&oatmp));
566 if (!oa) {
567 DPRINTF("generate\n");
568 if (out_addrs->count() > 1024) {
569 reset();
570 delete addr;
571 addr = Addr->clone();
572 }
573 oa = new OutAddr(Addr, current_time);
574 generateAddr(Addr, oa);
575 out_addrs->insert(oa);
576 } else {
577 DPRINTF("but cached2 ");
578 if (oa->time != current_time) {
579 DPRINTF("(and generate)");
580 generateAddr(Addr, oa);
581 oa->updateTime(current_time);
582 }
583 DPRINTF("\n");
584 }
585 cur_out_addr = oa;
586 } else {
587 DPRINTF("Cached! ");
588 if (cur_out_addr->time != current_time) {
589 DPRINTF("(but generate)");
590 generateAddr(Addr, cur_out_addr);
591 cur_out_addr->updateTime(current_time);
592 }
593 DPRINTF("\n");
594 }
595 return cur_out_addr;
596 }
597
getLine(Address * Addr,int line)598 OutLine *AnalyserOutput::getLine(Address *Addr, int line)
599 {
600 return getAddr(Addr)->getLine(line);
601 }
602
getLineString(char * buf,int maxlen,Address * Addr,int line)603 bool AnalyserOutput::getLineString(char *buf, int maxlen, Address *Addr, int line)
604 {
605 OutLine *ol = getLine(Addr, line);
606 if (ol) {
607 if (maxlen>0) {
608 int len = MIN(ol->textlen+1, maxlen);
609 len--;
610 memcpy(buf, ol->text, len);
611 buf[len] = 0;
612 }
613 return true;
614 } else {
615 return false;
616 }
617 }
618
getLineByteLength(int & len,Address * Addr,int line)619 bool AnalyserOutput::getLineByteLength(int &len, Address *Addr, int line)
620 {
621 OutLine *ol = getLine(Addr, line);
622 if (ol) {
623 len = ol->bytes;
624 return true;
625 } else {
626 return false;
627 }
628 }
629
getLineCount(Address * Addr)630 int AnalyserOutput::getLineCount(Address *Addr)
631 {
632 return getAddr(Addr)->lines->count();
633 }
634
getAddrByteLength(Address * Addr)635 int AnalyserOutput::getAddrByteLength(Address *Addr)
636 {
637 return getAddr(Addr)->bytes;
638 }
639
header()640 void AnalyserOutput::header()
641 {
642 // STUB
643 }
644
link(char * s,Address * Addr)645 char *AnalyserOutput::link(char *s, Address *Addr)
646 {
647 strcpy((char*)temp_buffer, s);
648 return (char*)temp_buffer;
649 }
650
externalLink(char * s,uint32 type1,uint32 type2,uint32 type3,uint32 type4,void * special)651 char *AnalyserOutput::externalLink(char *s, uint32 type1, uint32 type2, uint32 type3, uint32 type4, void *special)
652 {
653 strcpy((char*)temp_buffer, s);
654 return (char*)temp_buffer;
655 }
656
invalidateCache()657 void AnalyserOutput::invalidateCache()
658 {
659 DPRINTF("invalidateCache()\n");
660 current_time++;
661 if ((current_time % 50)==0) {
662 // collect garbage
663 reset();
664 }
665 }
666
nextLine(Address * & Addr,int & line,int n,Address * max)667 int AnalyserOutput::nextLine(Address *&Addr, int &line, int n, Address *max)
668 {
669 int res = 0;
670 int len;
671 while (n--) {
672 if (getLineByteLength(len, Addr, line + 1)) {
673 line++;
674 } else {
675 getLineByteLength(len, Addr, line);
676 if (Addr->compareTo(max) >= 0) return res;
677 if (!Addr->add(len)) return res;
678 line = 0;
679 }
680 res++;
681 }
682 return res;
683 }
684
prevLine(Address * & Addr,int & line,int n,Address * min)685 int AnalyserOutput::prevLine(Address *&Addr, int &line, int n, Address *min)
686 {
687 //#undef DPRINTF2
688 //#define DPRINTF2(msg...) {ht_snprintf(tbuf, 1024, msg); fprintf(stderr, "%s", tbuf);}
689 // char tbuf[1024];
690 DPRINTF2("prev_line(%y, %d, %d, %y)\n", Addr, line, n, min);
691
692 int res = 0;
693 int cmp = Addr->compareTo(min);
694
695 DPRINTF2("cmp=%d\n", cmp);
696 /*
697 * If we have reached |min| and line==0, we're on top
698 */
699 if (cmp < 0 || (cmp == 0 && line == 0)) {
700 DPRINTF2("geht nicht\n");
701 return 0;
702 }
703 /*
704 * A simple case: no address-change, only line-changes.
705 * Go up while line > 0
706 */
707 while (n && line) {
708 DPRINTF2("simple\n");
709 n--;
710 line--;
711 res++;
712 }
713 DPRINTF2("test\n");
714 if (!n) return res;
715 DPRINTF2("test2\n");
716
717 /*
718 * Now it gets complicated. We have to go to an other address.
719 * First we have to figure out where we should start to search for
720 * the previous address.
721 */
722 int min_length, max_length, min_look_ahead, avg_look_ahead, addr_align;
723 if (analy->disasm) {
724 analy->disasm->getOpcodeMetrics(min_length, max_length, min_look_ahead, avg_look_ahead, addr_align);
725 } else {
726 min_look_ahead = 1;
727 avg_look_ahead = 1;
728 }
729
730 int l = n*avg_look_ahead;
731 if (l < min_look_ahead) l = min_look_ahead;
732
733 /*
734 * The disassember whats us to go |l| bytes back
735 */
736
737 Address *search_addr = Addr->clone();
738 if (!search_addr->add(-l) || search_addr->compareTo(min) < 0) {
739 /*
740 * It isnt possible, to go |l| bytes back. So we start at |min|.
741 */
742 delete search_addr;
743 search_addr = min->clone();
744 }
745 DPRINTF2("search-start: %y\n", search_addr);
746
747 /*
748 * |prev| contains the previous "logical" location.
749 * That is some address known to be "atomic".
750 */
751 Location *prev = analy->enumLocationsReverse(Addr);
752 if (prev) {
753 DPRINTF2("prev: %y\n", prev->addr);
754 /*
755 * |prevnext| contains the "end address" of |prev|.
756 * So we know how long (how much bytes) prev is.
757 */
758 Address *prevnext = prev->addr->clone();
759 if (prevnext->add(getAddrByteLength(prev->addr))) {
760 DPRINTF2("mid-test: prevnext %y\n", prevnext);
761 if (prevnext->compareTo(Addr) > 0) {
762 /*
763 * We were in the middle of a location.
764 * We solve this situation by starting a new search
765 * with |prev->addr|. This is counted as "one line up".
766 */
767 delete Addr;
768 delete search_addr;
769 delete prevnext;
770 Addr = prev->addr->clone();
771 line = 0;
772 res++;
773 DPRINTF2("mid\n");
774 return prevLine(Addr, line, n-1, min)+res;
775 }
776 if (prevnext->compareTo(Addr) == 0) {
777 delete Addr;
778 delete search_addr;
779 delete prevnext;
780 Addr = prev->addr->clone();
781 line = getLineCount(prev->addr)-1;
782 res++;
783 DPRINTF2("mid2\n");
784 return prevLine(Addr, line, n-1, min)+res;
785 }
786 DPRINTF2("prev: %y prevnext: %y search_addr: %y\n", prev->addr, prevnext, search_addr);
787 Address *oldprevnext = prevnext->clone();
788 if (prevnext->add(l) && prevnext->compareTo(Addr) >= 0) {
789 delete search_addr;
790 search_addr = oldprevnext;
791 DPRINTF2("prevnext: %y Addr: %y\n", prevnext, Addr);
792 DPRINTF2("search_addr: %y\n", search_addr);
793 DPRINTF2("mid3\n");
794 } else {
795 delete oldprevnext;
796 }
797 }
798 delete prevnext;
799 }
800
801 int search_line = 0;
802 if (search_addr->compareTo(min) < 0) {
803 /*
804 * We have to start the search at |min|.
805 */
806 DPRINTF2("search_addr < min\n");
807 delete search_addr;
808 search_addr = min->clone();
809 }
810
811 Address *addrbuf[1024];
812 int linebuf[1024];
813 int i = 0;
814 int len;
815
816 Address *next_addr = search_addr->clone();
817 while (1) {
818 DPRINTF2("search_addr: (%y, %d) ", search_addr, search_line);
819 DPRINTF2("next_addr: %y \n", next_addr);
820 if (search_addr->compareTo(Addr) >= 0) {
821 if (search_line >= line || (search_addr->compareTo(Addr) > 0)) break;
822 }
823 if (getLineByteLength(len, search_addr, search_line)) {
824 next_addr->add(len);
825 search_line++;
826 } else {
827 delete search_addr;
828 search_addr = next_addr->clone();
829 search_line = 0;
830 continue;
831 }
832 addrbuf[i & 1023] = search_addr->clone();
833 linebuf[i & 1023] = search_line-1;
834 i++;
835 if (i >= 1023) break;
836 }
837
838 delete next_addr;
839 delete search_addr;
840
841 if (!i) {
842 DPRINTF2("no i!\n");
843 return res;
844 }
845 delete Addr;
846 if (i >= n) {
847 Addr = addrbuf[(i-n) & 1023]->clone();
848 line = linebuf[(i-n) & 1023];
849 res += n;
850 n = 0;
851 } else {
852 Addr = addrbuf[0]->clone();
853 line = linebuf[0];
854 res += i;
855 n -= i;
856 }
857
858 for (int j=0; j < i; j++) delete addrbuf[j];
859
860 if (n) return prevLine(Addr, line, n, min) + res;
861 return res;
862 }
863
putElement(int element_type,const char * element)864 void AnalyserOutput::putElement(int element_type, const char *element)
865 {
866 write(element);
867 }
868
reset()869 void AnalyserOutput::reset()
870 {
871 delete addr;
872 addr = new InvalidAddress;
873 cur_out_addr = NULL;
874 out_addrs->delAll();
875 }
876
write(const char * s)877 void AnalyserOutput::write(const char *s)
878 {
879 int len = elementLength(s);
880 len = MIN(len, work_buffer_end-work_buffer);
881 memcpy(work_buffer, s, len);
882 work_buffer += len;
883 }
884
write(const char * s,int n)885 void AnalyserOutput::write(const char *s, int n)
886 {
887 n = MIN(n, work_buffer_end-work_buffer);
888 memcpy(work_buffer, s, n);
889 work_buffer += n;
890 }
891