1 /*
2  *	HT Editor
3  *	analy_java.cc
4  *
5  *	Copyright (C) 1999-2002 Sebastian Biallas (sb@biallas.net)
6  *
7  *	This program is free software; you can redistribute it and/or modify
8  *	it under the terms of the GNU General Public License version 2 as
9  *	published by the Free Software Foundation.
10  *
11  *	This program is distributed in the hope that it will be useful,
12  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *	GNU General Public License for more details.
15  *
16  *	You should have received a copy of the GNU General Public License
17  *	along with this program; if not, write to the Free Software
18  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include <string.h>
22 
23 #include "analy_register.h"
24 #include "analy_java.h"
25 #include "htdebug.h"
26 #include "javadis.h"
27 #include "strtools.h"
28 #include "snprintf.h"
29 
init(Analyser * A,java_token_func token_func,void * context)30 void AnalyJavaDisassembler::init(Analyser *A, java_token_func token_func, void *context)
31 {
32 	disasm = new javadis(token_func, context);
33 	AnalyDisassembler::init(A);
34 }
35 
36 /*
37  *
38  */
getObjectID() const39 ObjectID AnalyJavaDisassembler::getObjectID() const
40 {
41 	return ATOM_ANALY_JAVA;
42 }
43 
44 /*
45  *
46  */
47 
branchAddr(OPCODE * opcode,branch_enum_t branchtype,bool examine)48 Address *AnalyJavaDisassembler::branchAddr(OPCODE *opcode, branch_enum_t branchtype, bool examine)
49 {
50 	javadis_insn *o = (javadis_insn*)opcode;
51 	switch (o->op[0].type) {
52 	case JAVA_OPTYPE_LABEL:
53 		return new AddressFlat32(o->op[0].label);
54 	}
55 	return new InvalidAddress();
56 }
57 
read4(Analyser * a,Address & addr,byte * b)58 static uint32 read4(Analyser *a, Address &addr, byte *b)
59 {
60 	if (a->bufPtr(&addr, b, 4) != 4) throw 1;
61 	addr.add(4);
62 	return (b[0]<<24) | (b[1]<<16) | (b[2]<<8) | b[3];
63 }
64 
examineOpcode(OPCODE * opcode)65 void AnalyJavaDisassembler::examineOpcode(OPCODE *opcode)
66 {
67 	javadis_insn *o = (javadis_insn*)opcode;
68 	const char *opcode_str = o->name;
69 	if (strcmp("lookupswitch", opcode_str) == 0) {
70 		uint32 ofs = o->addr;
71 		AddressFlat32 c(ofs);
72 		Location *loc = analy->getFunctionByAddress(&c);
73 		if (loc) {
74 			AddressFlat32 *func = (AddressFlat32 *)loc->addr;
75 			uint32 f = func->addr;
76 			ofs = ofs+1 - f;
77 			while (ofs % 4) {
78 				AddressFlat32 iofs(f+ofs);
79 				analy->data->setIntAddressType(&iofs, dst_ibyte, 1);
80 				ofs++;
81 			}
82 			AddressFlat32 iofs(f + ofs);
83 			byte buf[4];
84 			try {
85 				analy->data->setIntAddressType(&iofs, dst_idword, 4);
86 				uint32 default_ofs = read4(analy, iofs, buf);
87 				analy->data->setIntAddressType(&iofs, dst_idword, 4);
88 				uint32 n = read4(analy, iofs, buf);
89 
90 				for (uint32 i=0; i < n; i++) {
91 					char buffer[100];
92 					analy->data->setIntAddressType(&iofs, dst_idword, 4);
93 					uint32 value = read4(analy, iofs, buf);
94 					analy->data->setIntAddressType(&iofs, dst_idword, 4);
95 					uint32 rel_ofs = read4(analy, iofs, buf);
96 					AddressFlat32 a(o->addr + rel_ofs);
97 					if (!analy->getLocationByAddress(&a)) analy->addComment(&a, 0, "");
98 					ht_snprintf(buffer, sizeof buffer, "lookupswitch value: %d", value);
99 					analy->addComment(&a, 0, buffer);
100 					analy->addAddressSymbol(&a, "lookup", label_loc, loc);
101 					analy->pushAddress(&a, func);
102 					analy->addXRef(&a, &c, xrefijump);
103 				}
104 				AddressFlat32 a(o->addr + default_ofs);
105 				analy->addComment(&a, 0, "");
106 				analy->addComment(&a, 0, "lookupswitch default");
107 				analy->addAddressSymbol(&a, "lookup", label_loc, loc);
108 				analy->pushAddress(&a, func);
109 				analy->addXRef(&a, &c, xrefijump);
110 			} catch (...) {
111 				return;
112 			}
113 		}
114 	} else if (strcmp("tableswitch", opcode_str) == 0) {
115 		uint32 ofs = o->addr;
116 		AddressFlat32 c(ofs);
117 		Location *loc = analy->getFunctionByAddress(&c);
118 		if (loc) {
119 			AddressFlat32 *func = (AddressFlat32 *)loc->addr;
120 			uint32 f = func->addr;
121 			ofs = ofs+1 - f;
122 			while (ofs % 4) {
123 				AddressFlat32 iofs(f+ofs);
124 				analy->data->setIntAddressType(&iofs, dst_ibyte, 1);
125 				ofs++;
126 			}
127 			AddressFlat32 iofs(f + ofs);
128 			byte buf[4];
129 			try {
130 				analy->data->setIntAddressType(&iofs, dst_idword, 4);
131 				uint32 default_ofs = read4(analy, iofs, buf);
132 				analy->data->setIntAddressType(&iofs, dst_idword, 4);
133 				sint32 low = read4(analy, iofs, buf);
134 				analy->data->setIntAddressType(&iofs, dst_idword, 4);
135 				sint32 high = read4(analy, iofs, buf);
136 
137 				for (sint32 i=low; i <= high; i++) {
138 					char buffer[100];
139 					analy->data->setIntAddressType(&iofs, dst_idword, 4);
140 					uint32 rel_ofs = read4(analy, iofs, buf);
141 					AddressFlat32 a(o->addr + rel_ofs);
142 					if (!analy->getLocationByAddress(&a)) analy->addComment(&a, 0, "");
143 					ht_snprintf(buffer, sizeof buffer, "tableswitch value: %d", i);
144 					analy->addComment(&a, 0, buffer);
145 					analy->addAddressSymbol(&a, "table", label_loc, loc);
146 					analy->pushAddress(&a, func);
147 					analy->addXRef(&a, &c, xrefijump);
148 				}
149 				AddressFlat32 a(o->addr + default_ofs);
150 				analy->addComment(&a, 0, "");
151 				analy->addComment(&a, 0, "tableswitch default");
152 				analy->addAddressSymbol(&a, "table", label_loc, loc);
153 				analy->pushAddress(&a, func);
154 				analy->addXRef(&a, &c, xrefijump);
155 			} catch (...) {
156 				return;
157 			}
158 		}
159 	}
160 }
161 
162 /*
163  *
164  */
isBranch(OPCODE * opcode)165 branch_enum_t AnalyJavaDisassembler::isBranch(OPCODE *opcode)
166 {
167 	javadis_insn *o = (javadis_insn*)opcode;
168 	const char *opcode_str = o->name;
169 	if ((opcode_str[0]=='i') && (opcode_str[1]=='f')) {
170 		return br_jXX;
171 	} else if ((strcmp("tableswitch", opcode_str)==0)
172 	|| (strcmp("lookupswitch", opcode_str)==0)) {
173 		examineOpcode(opcode);
174 		return br_jump;
175 	} else if (ht_strncmp("ret", opcode_str, 3)==0
176 	|| ht_strncmp("ret", opcode_str+1, 3)==0
177 	|| ht_strncmp("athrow", opcode_str, 6)==0) {
178 		return br_return;
179 	} else if (ht_strncmp("goto", opcode_str, 4)==0) {
180 		return br_jump;
181 	} else if (ht_strncmp("jsr", opcode_str, 3)==0) {
182 		return br_call;
183 	} else return br_nobranch;
184 }
185