1 /* radare2 - LGPL - Copyright 2018-2019 - pancake */
2 
3 #include <r_bin.h>
4 
5 typedef struct {
6 	bool rust;
7 	bool objc;
8 	bool dlang;
9 	bool swift;
10 	bool cxx;
11 	bool msvc;
12 } Langs;
13 
check_rust(RBinSymbol * sym)14 static inline bool check_rust(RBinSymbol *sym) {
15 	return sym->name && strstr (sym->name, "_$LT$");
16 }
17 
check_objc(RBinSymbol * sym)18 static inline bool check_objc(RBinSymbol *sym) {
19 	if (sym->name && !strncmp (sym->name, "_OBJC_", 6)) {
20 		// free (r_bin_demangle_objc (binfile, sym->name));
21 		return true;
22 	}
23 	return false;
24 }
25 
check_dlang(RBinSymbol * sym)26 static bool check_dlang(RBinSymbol *sym) {
27 	if (!strncmp (sym->name, "_D2", 3)) {
28 		return true;
29 	}
30 	if (!strncmp (sym->name, "_D4", 3)) {
31 		return true;
32 	}
33 	return false;
34 }
35 
check_swift(RBinSymbol * sym)36 static bool check_swift(RBinSymbol *sym) {
37 	if (sym->name && strstr (sym->name, "swift_once")) {
38 		return true;
39 	}
40 	return false;
41 }
42 
check_golang(RBinSymbol * sym)43 static bool check_golang(RBinSymbol *sym) {
44 	return !strncmp (sym->name, "go.", 3);
45 }
46 
is_cxx_symbol(const char * name)47 static inline bool is_cxx_symbol (const char *name) {
48 	r_return_val_if_fail (name, false);
49 	if (!strncmp (name, "_Z", 2)) {
50 		return true;
51 	}
52 	if (!strncmp (name, "__Z", 3)) {
53 		return true;
54 	}
55 	return false;
56 }
57 
check_cxx(RBinSymbol * sym)58 static bool check_cxx(RBinSymbol *sym) {
59 	return is_cxx_symbol (sym->name);
60 }
61 
check_msvc(RBinSymbol * sym)62 static bool check_msvc(RBinSymbol *sym) {
63 	return *sym->name == '?';
64 }
65 
66 /* This is about 10% of the loading time, optimize if possible */
r_bin_load_languages(RBinFile * binfile)67 R_API int r_bin_load_languages(RBinFile *binfile) {
68 	r_return_val_if_fail (binfile, R_BIN_NM_NONE);
69 	r_return_val_if_fail (binfile->o, R_BIN_NM_NONE);
70 	r_return_val_if_fail (binfile->o->info, R_BIN_NM_NONE);
71 	RBinObject *o = binfile->o;
72 	RBinInfo *info = o->info;
73 	RBinSymbol *sym;
74 	RListIter *iter, *iter2;
75 	Langs cantbe = {0};
76 	bool phobosIsChecked = false;
77 	bool swiftIsChecked = false;
78 	bool canBeCxx = false;
79 	bool cxxIsChecked = false;
80 	bool isMsvc = false;
81 
82 	const char *ft = r_str_get (info->rclass);
83 	bool unknownType = info->rclass == NULL;
84 	bool isMacho = strstr (ft, "mach");
85 	bool isElf = strstr (ft, "elf");
86 	bool isPe = strstr (ft, "pe");
87 	bool isBlocks = false;
88 	bool isObjC = false;
89 
90 	if (unknownType || !(isMacho || isElf || isPe)) {
91 		return R_BIN_NM_NONE;
92 	}
93 
94 	// check in imports . can be slow
95 	r_list_foreach (o->imports, iter, sym) {
96 		const char *name = sym->name;
97 		if (!strcmp (name, "_NSConcreteGlobalBlock")) {
98 			isBlocks = true;
99 		} else if (!strncmp (name, "objc_", 5)) {
100 			isObjC = true;
101 			cantbe.objc = true;
102 		}
103 	}
104 
105 	r_list_foreach (o->symbols, iter, sym) {
106 		char *lib;
107 		if (!cantbe.rust) {
108 			if (check_rust (sym)) {
109 				info->lang = "rust";
110 				return R_BIN_NM_RUST;
111 			}
112 		}
113 		if (check_golang (sym)) {
114 			info->lang = "go";
115 			return R_BIN_NM_GO;
116 		}
117 		if (!cantbe.swift) {
118 			bool hasswift = false;
119 			if (!swiftIsChecked) {
120 				r_list_foreach (o->libs, iter2, lib) {
121 					if (strstr (lib, "swift")) {
122 						hasswift = true;
123 						break;
124 					}
125 				}
126 				swiftIsChecked = true;
127 			}
128 			if (hasswift || check_swift (sym)) {
129 				info->lang = "swift";
130 				return R_BIN_NM_SWIFT;
131 			}
132 		}
133 		if (!cantbe.cxx) {
134 			bool hascxx = false;
135 			if (!cxxIsChecked) {
136 				r_list_foreach (o->libs, iter2, lib) {
137 					if (strstr (lib, "stdc++") ||
138 					    strstr (lib, "c++")) {
139 						hascxx = true;
140 						break;
141 					}
142 					if (strstr (lib, "msvcp")) {
143 						info->lang = "msvc";
144 						return R_BIN_NM_MSVC;
145 					}
146 				}
147 				cxxIsChecked = true;
148 			}
149 			if (hascxx || check_cxx (sym)) {
150 				canBeCxx = true;
151 				cantbe.cxx = true;
152 			}
153 		}
154 		if (!cantbe.objc) {
155 			if (check_objc (sym)) {
156 				info->lang = "objc";
157 				return R_BIN_NM_OBJC;
158 			}
159 		}
160 		if (!cantbe.dlang) {
161 			bool hasdlang = false;
162 			if (!phobosIsChecked) {
163 				r_list_foreach (o->libs, iter2, lib) {
164 					if (strstr (lib, "phobos")) {
165 						hasdlang = true;
166 						break;
167 					}
168 				}
169 				phobosIsChecked = true;
170 			}
171 			if (hasdlang || check_dlang (sym)) {
172 				info->lang = "dlang";
173 				return R_BIN_NM_DLANG;
174 			}
175 		}
176 		if (!cantbe.msvc) {
177 			if (!isMsvc && check_msvc (sym)) {
178 				isMsvc = true;
179 			}
180 		}
181 	}
182 	if (isObjC) {
183 		return R_BIN_NM_OBJC | (isBlocks?R_BIN_NM_BLOCKS:0);
184 	}
185 	if (canBeCxx) {
186 		return R_BIN_NM_CXX | (isBlocks?R_BIN_NM_BLOCKS:0);
187 	}
188 	if (isMsvc) {
189 		return R_BIN_NM_MSVC;
190 	}
191 	return R_BIN_NM_C | (isBlocks?R_BIN_NM_BLOCKS:0);
192 }
193 
r_bin_lang_type(RBinFile * binfile,const char * def,const char * sym)194 R_IPI int r_bin_lang_type(RBinFile *binfile, const char *def, const char *sym) {
195 	int type = 0;
196 	RBinPlugin *plugin;
197 	if (sym && sym[0] == sym[1] && sym[0] == '_') {
198 		type = R_BIN_NM_CXX;
199 	}
200 	if (def && *def) {
201 		type = r_bin_demangle_type (def);
202 		if (type != R_BIN_NM_NONE) {
203 			return type;
204 		}
205 	}
206 	plugin = r_bin_file_cur_plugin (binfile);
207 	if (plugin && plugin->demangle_type) {
208 		type = plugin->demangle_type (def);
209 	} else {
210 		if (binfile && binfile->o && binfile->o->info) {
211 			type = r_bin_demangle_type (binfile->o->info->lang);
212 		}
213 	}
214 	if (type == R_BIN_NM_NONE) {
215 		type = r_bin_demangle_type (def);
216 	}
217 	return type;
218 }
219 
r_bin_lang_tostring(int lang)220 R_API const char *r_bin_lang_tostring(int lang) {
221 	switch (lang & 0xffff) {
222 	case R_BIN_NM_SWIFT:
223 		return "swift";
224 	case R_BIN_NM_GO:
225 		return "go";
226 	case R_BIN_NM_JAVA:
227 		return "java";
228 	case R_BIN_NM_KOTLIN:
229 		return "kotlin";
230 	case R_BIN_NM_C:
231 		return (lang & R_BIN_NM_BLOCKS)? "c with blocks": "c";
232 	case R_BIN_NM_CXX:
233 		return (lang & R_BIN_NM_BLOCKS)? "c++ with blocks": "c++";
234 	case R_BIN_NM_DLANG:
235 		return "d";
236 	case R_BIN_NM_OBJC:
237 		return (lang & R_BIN_NM_BLOCKS)? "objc with blocks": "objc";
238 	case R_BIN_NM_MSVC:
239 		return "msvc";
240 	case R_BIN_NM_RUST:
241 		return "rust";
242 	}
243 	return NULL;
244 }
245 
246