File: aranges.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 (64 lines) | stat: -rw-r--r-- 1,689 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
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use debug::image;
use errors;
use format::elf;
use io;

// Supported version of .debug_aranges decoder
def ARANGES_VERSION: u16 = 2;

// Returns the debug_info offset for the DIE that corresponds to this address,
// if known, or void if unknown.
export fn arange_lookup(
	image: *image::image,
	addr: uintptr,
) (u64 | void | errors::invalid) = {
	const aranges = match (image::section_byname(image, ".debug_aranges")) {
	case let sec: *elf::section64 =>
		yield sec;
	case null =>
		return;
	};

	// Read all arange tables in this section
	const rd = image::section_reader(image, aranges);
	for (const rd => new_table_reader(&rd, true)!) {
		match (arange_match(&rd, addr)) {
		case void => void;
		case let u: u64 =>
			return u;
		case io::error =>
			return errors::invalid;
		};
	};
};

fn arange_match(rd: *table_reader, addr: uintptr) (u64 | void | io::error) = {
	const ver = read_uhalf(rd)?;
	const info_offset = read_secword(rd)?;
	const asize = read_ubyte(rd)?;
	const ssize = read_ubyte(rd)?;
	assert(ver == ARANGES_VERSION, "debug::dwarf: unsupported .debug_ranges version");
	assert(ssize == 0, "debug::dwarf: unsupported segmented target for .debug_aranges");
	assert(asize == 8, "debug::dwarf: unsupported address size for .debug_aranges");

	read_align(rd, asize * 2)?;

	const au64 = addr: u64;
	for (!read_iseof(rd)) {
		const min = read_ulong(rd)?;
		const length = read_ulong(rd)?;
		if (min == 0 && length == 0) {
			if (!read_iseof(rd)) {
				return errors::invalid;
			};
			break;
		};
		const max = min + length;
		if (min <= au64 && max > au64) {
			return info_offset;
		};
	};
};