File: abbrev.ha

package info (click to toggle)
hare 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,352 kB
  • sloc: asm: 1,374; makefile: 123; sh: 117; lisp: 101
file content (125 lines) | stat: -rw-r--r-- 2,689 bytes parent folder | download
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

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

export type abbrev_table = struct {
	items: []abbrev,
};

// A single abbreviated tag from a .debug_abbrev section.
export type abbrev = struct {
	code: u64,
	tag: u32,
	has_children: bool,
	fields: []afield,
};

// A field in a .debug_abbrev section
export type afield = struct {
	attr: u32,
	form: u32,
};

// Loads an abbreviation table from the .debug_abbrev section, loading the table
// at the provided offset from the start of the ELF section.
//
// Pass the result to [[abbrev_table_finish]] to free resources associated with
// the table when you're done with it.
export fn load_abbrevs(
	image: *image::image,
	offs: u64,
) (abbrev_table | void | errors::invalid | nomem) = {
	const sec = match (image::section_byname(image, ".debug_abbrev")) {
	case let sec: *elf::section64 =>
		yield sec;
	case null =>
		return;
	};

	const rd = image::section_reader(image, sec);
	io::seek(&rd, offs: io::off, io::whence::SET)!;
	const rd = new_table_reader(&rd, false)! as table_reader;

	let abbrevs: []abbrev = [];
	let ok = false;
	defer if (!ok) {
		free(abbrevs);
	};

	for (true) {
		match (read_abbrev(&rd)) {
		case io::EOF => break;
		case io::error => return errors::invalid;
		case nomem => return nomem;
		case let ab: abbrev =>
			append(abbrevs, ab)?;
		};
	};

	ok = true;
	return abbrev_table {
		items = abbrevs,
	};
};

// Reads an entry from an abbreviation table.
fn read_abbrev(
	rd: *table_reader,
) (abbrev | io::EOF | io::error | nomem) = {
	const code = read_uleb128(rd)?;
	if (code == 0) {
		return io::EOF;
	};
	const tag = read_uleb128(rd)?;
	const children = read_ubyte(rd)? != 0;

	let fields: []afield = [];
	let ok = false;
	defer if (!ok) {
		free(fields);
	};

	for (true) {
		const name = read_uleb128(rd)?;
		const form = read_uleb128(rd)?;
		if (name == 0 && form == 0) {
			break;
		};
		append(fields, afield {
			attr = name: u32,
			form = form: u32,
		})?;
	};

	ok = true;

	return abbrev {
		code = code,
		tag = tag: u32,
		has_children = children,
		fields = fields,
	};
};

// Frees resources associated with an [[abbrev_table]].
export fn abbrev_table_finish(table: *abbrev_table) void = {
	for (let i = 0z; i < len(table.items); i += 1) {
		free(table.items[i].fields);
	};
	free(table.items);
};

// Retrieves an abbreviation from an [[abbrev_table]] by its abbreviation code.
export fn get_abbrev(table: *abbrev_table, code: u64) const nullable *abbrev = {
	// TODO: Sort the list and do this faster
	for (let item &.. table.items) {
		if (item.code == code) {
			return item;
		};
	};
	return null;
};