static int bin_symbols_internal(RCore *r, int mode, ut64 laddr, int va, ut64 at, const char *name, bool exponly, const char *args) {
	RBinInfo *info = r_bin_get_info (r->bin);
	RList *entries = r_bin_get_entries (r->bin);
	RBinSymbol *symbol;
	RBinAddr *entry;
	RListIter *iter;
	RList *symbols;
	const char *lang;
	bool firstexp = true;
	bool printHere = false;
	int i = 0, is_arm, lastfs = 's';
	bool bin_demangle = r_config_get_i (r->config, "bin.demangle");
	if (!info) {
		return 0;
	}

	if (args && *args == '.') {
		printHere = true;
	}

	is_arm = info && info->arch && !strncmp (info->arch, "arm", 3);
	lang = bin_demangle ? r_config_get (r->config, "bin.lang") : NULL;

	symbols = r_bin_get_symbols (r->bin);
	r_space_set (&r->anal->meta_spaces, "bin");

	if (IS_MODE_JSON (mode) && !printHere) {
		r_cons_printf ("[");
	} else if (IS_MODE_SET (mode)) {
		r_flag_space_set (r->flags, "symbols");
	} else if (!at && exponly) {
		if (IS_MODE_RAD (mode)) {
			r_cons_printf ("fs exports\n");
		} else if (IS_MODE_NORMAL (mode)) {
			r_cons_printf (printHere ? "" : "[Exports]\n");
		}
	} else if (!at && !exponly) {
		if (IS_MODE_RAD (mode)) {
			r_cons_printf ("fs symbols\n");
		} else if (IS_MODE_NORMAL (mode)) {
			r_cons_printf (printHere ? "" : "[Symbols]\n");
		}
	}

	r_list_foreach (symbols, iter, symbol) {
		ut64 addr = rva (r->bin, symbol->paddr, symbol->vaddr, va);
		int len = symbol->size ? symbol->size : 32;
		SymName sn;

		if (exponly && !isAnExport (symbol)) {
			continue;
		}
		if (name && strcmp (symbol->name, name)) {
			continue;
		}
		if (at && (!symbol->size || !is_in_range (at, addr, symbol->size))) {
			continue;
		}
		if ((printHere && !is_in_range (r->offset, symbol->paddr, len))
				&& (printHere && !is_in_range (r->offset, addr, len))) {
			continue;
		}
		snInit (r, &sn, symbol, lang);

		if (IS_MODE_SET (mode) && (is_section_symbol (symbol) || is_file_symbol (symbol))) {
			/*
			 * Skip section symbols because they will have their own flag.
			 * Skip also file symbols because not useful for now.
			 */
		} else if (IS_MODE_SET (mode)) {
			if (is_arm && info->bits < 33) { // 16 or 32
				int force_bits = 0;
				if (symbol->paddr & 1 || symbol->bits == 16) {
					force_bits = 16;
				} else if (info->bits == 16 && symbol->bits == 32) {
					force_bits = 32;
				} else if (!(symbol->paddr & 1) && symbol->bits == 32) {
					force_bits = 32;
				}
				if (force_bits) {
					r_anal_hint_set_bits (r->anal, addr, force_bits);
				}
			}
			if (!strncmp (symbol->name, "imp.", 4)) {
				if (lastfs != 'i') {
					r_flag_space_set (r->flags, "imports");
				}
				lastfs = 'i';
			} else {
				if (lastfs != 's') {
					r_flag_space_set (r->flags, "symbols");
				}
				lastfs = 's';
			}
			/* If that's a Classed symbol (method or so) */
			if (sn.classname) {
				RFlagItem *fi = NULL;
				char *comment = NULL;
				fi = r_flag_get (r->flags, sn.methflag);
				if (r->bin->prefix) {
					char *prname;
					prname = r_str_newf ("%s.%s", r->bin->prefix, sn.methflag);
					r_name_filter (sn.methflag, -1);
					free (sn.methflag);
					sn.methflag = prname;
				}
				if (fi) {
					r_flag_item_set_realname (fi, sn.methname);
					if ((fi->offset - r->flags->base) == addr) {
						comment = fi->comment ? strdup (fi->comment) : NULL;
						r_flag_unset (r->flags, fi);
					}
				} else {
					fi = r_flag_set (r->flags, sn.methflag, addr, symbol->size);
					comment = fi->comment ? strdup (fi->comment) : NULL;
					if (comment) {
						r_flag_item_set_comment (fi, comment);
						R_FREE (comment);
					}
				}
			} else {
				const char *fn, *n;
				RFlagItem *fi;
				n = sn.demname ? sn.demname : sn.name;
				fn = sn.demflag ? sn.demflag : sn.nameflag;
				char *fnp = (r->bin->prefix) ?
					r_str_newf ("%s.%s", r->bin->prefix, fn):
					strdup (fn);
				fi = r_flag_set (r->flags, fnp, addr, symbol->size);
				if (fi) {
					r_flag_item_set_realname (fi, n);
				} else {
					if (fn) {
						eprintf ("[Warning] Can't find flag (%s)\n", fn);
					}
				}
				free (fnp);
			}
			if (sn.demname) {
				r_meta_add (r->anal, R_META_TYPE_COMMENT,
					addr, symbol->size, sn.demname);
			}
		} else if (IS_MODE_JSON (mode)) {
			char *str = r_str_utf16_encode (symbol->name, -1);
			// str = r_str_replace (str, "\"", "\\\"", 1);
			r_cons_printf ("%s{\"name\":\"%s\","
				"\"demname\":\"%s\","
				"\"flagname\":\"%s\","
				"\"ordinal\":%d,"
				"\"bind\":\"%s\","
				"\"size\":%d,"
				"\"type\":\"%s\","
				"\"vaddr\":%"PFMT64d","
				"\"paddr\":%"PFMT64d"}",
				((exponly && firstexp) || printHere) ? "" : (iter->p ? "," : ""),
				str,
				sn.demname? sn.demname: "",
				sn.nameflag,
				symbol->ordinal,
				symbol->bind,
				(int)symbol->size,
				symbol->type,
				(ut64)addr, (ut64)symbol->paddr);
			free (str);
		} else if (IS_MODE_SIMPLE (mode)) {
			const char *name = sn.demname? sn.demname: symbol->name;
			r_cons_printf ("0x%08"PFMT64x" %d %s\n",
				addr, (int)symbol->size, name);
		} else if (IS_MODE_SIMPLEST (mode)) {
			const char *name = sn.demname? sn.demname: symbol->name;
			r_cons_printf ("%s\n", name);
		} else if (IS_MODE_RAD (mode)) {
			RBinFile *binfile;
			RBinPlugin *plugin;
			char *name = strdup (sn.demname? sn.demname: symbol->name);
			r_name_filter (name, -1);
			if (!strncmp (name, "imp.", 4)) {
				if (lastfs != 'i')
					r_cons_printf ("fs imports\n");
				lastfs = 'i';
			} else {
				if (lastfs != 's') {
					r_cons_printf ("fs %s\n",
						exponly? "exports": "symbols");
				}
				lastfs = 's';
			}
			if (r->bin->prefix) {
				if (symbol->dup_count) {
					r_cons_printf ("f %s.sym.%s_%d %u 0x%08"PFMT64x"\n",
						r->bin->prefix, name, symbol->dup_count, symbol->size, addr);
				} else {
					r_cons_printf ("f %s.sym.%s %u 0x%08"PFMT64x"\n",
						r->bin->prefix, name, symbol->size, addr);
				}
			} else {
				if (symbol->dup_count) {
					r_cons_printf ("f sym.%s_%d %u 0x%08"PFMT64x"\n",
						name, symbol->dup_count, symbol->size, addr);
				} else {
					r_cons_printf ("f sym.%s %u 0x%08"PFMT64x"\n",
						name, symbol->size, addr);
				}
			}
			binfile = r_core_bin_cur (r);
			plugin = r_bin_file_cur_plugin (binfile);
			if (plugin && plugin->name) {
				if (!strncmp (plugin->name, "pe", 2)) {
					char *p, *module = strdup (symbol->name);
					p = strstr (module, ".dll_");
					if (p) {
						const char *symname = p + 5;
						*p = 0;
						if (r->bin->prefix) {
							r_cons_printf ("k bin/pe/%s/%d=%s.%s\n",
								module, symbol->ordinal, r->bin->prefix, symname);
						} else {
							r_cons_printf ("k bin/pe/%s/%d=%s\n",
								module, symbol->ordinal, symname);
						}
					}
					free (module);
				}
			}
		} else {
			const char *bind = r_str_get (symbol->bind);
			const char *type = r_str_get (symbol->type);
			const char *name = r_str_get (sn.demname? sn.demname: symbol->name);
			// const char *fwd = r_str_get (symbol->forwarder);
			r_cons_printf ("%03u 0x%08"PFMT64x" 0x%08"PFMT64x" "
				"%6s %6s %4d %s\n",
				symbol->ordinal,
				symbol->paddr, addr, bind, type,
				symbol->size, name);
			// r_cons_printf ("vaddr=0x%08"PFMT64x" paddr=0x%08"PFMT64x" ord=%03u "
			//	"fwd=%s sz=%u bind=%s type=%s name=%s\n",
			//	addr, symbol->paddr, symbol->ordinal, fwd,
			//	symbol->size, bind, type, name);
		}
		snFini (&sn);
		i++;
		if (exponly && firstexp) {
			firstexp = false;
		}
		if (printHere) {
			break;
		}
	}

	//handle thumb and arm for entry point since they are not present in symbols
	if (is_arm) {
		r_list_foreach (entries, iter, entry) {
			if (IS_MODE_SET (mode)) {
				if (info->bits < 33) { // 16 or 32
					int force_bits = 0;
					ut64 addr = rva (r->bin, entry->paddr, entry->vaddr, va);
					if (entry->paddr & 1 || entry->bits == 16) {
						force_bits = 16;
					} else if (info->bits == 16 && entry->bits == 32) {
						force_bits = 32;
					} else if (!(entry->paddr & 1)) {
						force_bits = 32;
					}
					if (force_bits) {
						r_anal_hint_set_bits (r->anal, addr, force_bits);
					}
				}
			}
		}
	}
	if (IS_MODE_JSON (mode) && !printHere) r_cons_printf ("]");
#if 0
	if (IS_MODE_NORMAL (mode) && !at) {
		r_cons_printf ("\n%i %s\n", i, exponly ? "exports" : "symbols");
	}
#endif

	r_space_set (&r->anal->meta_spaces, NULL);
	return true;
}