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