File: sections.ha

package info (click to toggle)
hare 0.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,948 kB
  • sloc: asm: 1,264; makefile: 123; sh: 114; lisp: 101
file content (103 lines) | stat: -rw-r--r-- 2,649 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use format::elf;
use format::elf::{sht};
use types::c;
use memio;

// Check that this section is actually a reference to this image.
fn section_validate(image: *image, sec: *elf::section64) void = {
	const addr = sec: uintptr;
	const min = &image.data[0]: uintptr;
	const max = min + len(image.data): uintptr;
	assert(min <= addr && max > addr, "section_name: invalid section");
};

// Returns a program section by name. Returns null if there is no such section,
// or if the section names are not available in this image (e.g. because it was
// stripped).
export fn section_byname(
	image: *image,
	name: str,
) nullable *elf::section64 = {
	const cached = [
		(".symtab", &image.symtab),
		(".strtab", &image.strtab),
		(".debug_abbr", &image.debug_abbr),
		(".debug_aranges", &image.debug_aranges),
		(".debug_info", &image.debug_info),
		(".debug_line", &image.debug_line),
		(".debug_str", &image.debug_str),
	];
	for (const (cand, val) .. cached) {
		if (cand == name) {
			match (*val) {
			case null => break;
			case let sec: *elf::section64 =>
				return sec;
			};
		};
	};

	const head = image.header;
	let r: nullable *elf::section64 = null;
	for (let i = 0u16; i < head.e_shnum; i += 1) {
		const shoffs = head.e_shoff + i * head.e_shentsize;
		const sec = &image.data[shoffs]: *elf::section64;
		if (sec.sh_type == sht::NULL) {
			continue;
		};

		const cand = section_name(image, sec);
		if (cand == name) {
			r = sec;
			break;
		};
	};

	match (r) {
	case null =>
		return null;
	case let sec: *elf::section64 =>
		for (let (cand, val) .. cached) {
			if (cand == name) {
				*val = sec;
				break;
			};
		};
	};

	return r;
};

// Returns the name of this [[elf::section64]], returning "" if the section
// names are not available in this image (i.e. it has been stripped).
export fn section_name(
	image: *image,
	sec: *elf::section64,
) const str = {
	section_validate(image, sec);

	const shtab = match (image.shstrtab) {
	case let sec: *elf::section64 =>
		yield sec;
	case null =>
		return "";
	};

	const offs = shtab.sh_offset + sec.sh_name;
	return c::tostr(&image.data[offs]: *const c::char)!;
};

// Returns a slice of the data contained with a given section.
export fn section_data(image: *image, sec: *elf::section64) []u8 = {
	section_validate(image, sec);
	return image.data[sec.sh_offset..sec.sh_offset+sec.sh_size];
};

// Returns a [[memio::fixed]] reader for the given section.
export fn section_reader(image: *image, sec: *elf::section64) memio::stream = {
	const data = section_data(image, sec);
	return memio::fixed(data);
};