hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

symbols.ha (2583B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bytes;
      5 use debug::image;
      6 use io;
      7 use format::elf;
      8 use strings;
      9 use types::c;
     10 
     11 // Returns symbol information by name.
     12 export fn symbol_byname(
     13 	image: *image::image,
     14 	name: str,
     15 ) (elf::sym64 | io::error | void) = {
     16 	const strtab = match (image::section_byname(image, ".strtab")) {
     17 	case let sec: *elf::section64 =>
     18 		yield sec;
     19 	case null =>
     20 		return;
     21 	};
     22 	const symtab = match (image::section_byname(image, ".symtab")) {
     23 	case let sec: *elf::section64 =>
     24 		yield sec;
     25 	case null =>
     26 		return;
     27 	};
     28 
     29 	const st_name = scan_strtab(image, strtab, name) as u64;
     30 	const data = image::section_data(image, symtab);
     31 	const entsz = symtab.sh_entsize: size;
     32 	const nsym = len(data) / entsz;
     33 	for (let i = 0z; i < nsym; i += 1) {
     34 		const sym = &data[i * entsz]: *elf::sym64;
     35 		if (sym.st_name == st_name) {
     36 			return *sym;
     37 		};
     38 	};
     39 };
     40 
     41 // Returns the symbol that occupies a given address.
     42 export fn symbol_byaddr(
     43 	image: *image::image,
     44 	addr: uintptr,
     45 ) (elf::sym64 | io::error | void) = {
     46 	const addr = addr: u64;
     47 	const symtab = match (image::section_byname(image, ".symtab")) {
     48 	case let sec: *elf::section64 =>
     49 		yield sec;
     50 	case null =>
     51 		return;
     52 	};
     53 
     54 	const data = image::section_data(image, symtab);
     55 	const entsz = symtab.sh_entsize: size;
     56 	const nsym = len(data) / entsz;
     57 	for (let i = 0z; i < nsym; i += 1) {
     58 		const sym = &data[i * entsz]: *elf::sym64;
     59 		const min = sym.st_value;
     60 		const max = sym.st_value + sym.st_size;
     61 		if (min <= addr && addr < max) {
     62 			return *sym;
     63 		};
     64 	};
     65 };
     66 
     67 // Returns the name of the given symbol, or void if the executable was stripped.
     68 export fn symbol_name(
     69 	image: *image::image,
     70 	sym: *elf::sym64,
     71 ) (const str | io::error | void) = {
     72 	const strtab = match (image::section_byname(image, ".strtab")) {
     73 	case let sec: *elf::section64 =>
     74 		yield sec;
     75 	case null =>
     76 		return;
     77 	};
     78 	const data = image::section_data(image, strtab);
     79 	return c::tostr(&data[sym.st_name]: *const c::char)!;
     80 };
     81 
     82 // Scans a string table for a given name and returns the index of that name.
     83 fn scan_strtab(
     84 	image: *image::image,
     85 	strtab: *elf::section64,
     86 	name: str,
     87 ) (u64 | io::error | void) = {
     88 	let buf: [4096]u8 = [0...];
     89 	let namebuf: [MAX_SYMNAME]u8 = [0...];
     90 
     91 	// Prepare a nul-terminated byte slice of the name
     92 	let name = strings::toutf8(name);
     93 	namebuf[..len(name)] = name;
     94 	namebuf[len(name)] = 0;
     95 	name = namebuf[..len(name)+1];
     96 
     97 	const data = image::section_data(image, strtab);
     98 	match (bytes::index(data, name)) {
     99 	case let z: size =>
    100 		return z: u64;
    101 	case void => void;
    102 	};
    103 };