dwarf.c 21.2 KB
Newer Older
Luuk van Dijk's avatar
Luuk van Dijk committed
1 2 3 4
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

Luuk van Dijk's avatar
Luuk van Dijk committed
5 6 7 8 9
#include	"l.h"
#include	"lib.h"
#include	"../ld/dwarf.h"
#include	"../ld/dwarf_defs.h"
#include	"../ld/elf.h"
Luuk van Dijk's avatar
Luuk van Dijk committed
10
#include	"../ld/macho.h"
Luuk van Dijk's avatar
Luuk van Dijk committed
11 12

/*
Luuk van Dijk's avatar
Luuk van Dijk committed
13
 * Offsets and sizes of the debug_* sections in the cout file.
Luuk van Dijk's avatar
Luuk van Dijk committed
14 15 16 17 18 19 20 21
 */

static vlong abbrevo;
static vlong abbrevsize;
static vlong lineo;
static vlong linesize;
static vlong infoo;
static vlong infosize;
Luuk van Dijk's avatar
Luuk van Dijk committed
22 23
static vlong frameo;
static vlong framesize;
Luuk van Dijk's avatar
Luuk van Dijk committed
24

Luuk van Dijk's avatar
Luuk van Dijk committed
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
/*
 *  Basic I/O
 */

static void
addrput(vlong addr)
{
	switch(PtrSize) {
	case 4:
		LPUT(addr);
		break;
	case 8:
		VPUT(addr);
		break;
	}
}


static int
uleb128enc(uvlong v, char* dst)
{
	uint8 c, len;

	len = 0;
	do {
		c = v & 0x7f;
		v >>= 7;
		if (v)
			c |= 0x80;
		if (dst)
			*dst++ = c;
		len++;
	} while (c & 0x80);
	return len;
};


static int
sleb128enc(vlong v, char *dst)
{
	uint8 c, s, len;

	len = 0;
	do {
		c = v & 0x7f;
		s = v & 0x40;
		v >>= 7;
		if ((v != -1 || !s) && (v != 0 || s))
			c |= 0x80;
		if (dst)
			*dst++ = c;
		len++;
	} while(c & 0x80);
	return len;
}

static void
uleb128put(vlong v)
{
	char buf[10];
	strnput(buf, uleb128enc(v, buf));
}

static void
sleb128put(vlong v)
{
	char buf[10];
	strnput(buf, sleb128enc(v, buf));
}
Luuk van Dijk's avatar
Luuk van Dijk committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

/*
 * Defining Abbrevs.  This is hardcoded, and there will be
 * only a handful of them.  The DWARF spec places no restriction on
 * the ordering of atributes in the Abbrevs and DIEs, and we will
 * always write them out in the order of declaration in the abbrev.
 * This implementation relies on tag, attr < 127, so they serialize as
 * a char, hence we do not support user-defined tags or attributes.
 */
typedef struct DWAttrForm DWAttrForm;
struct DWAttrForm {
	uint8 attr;
	uint8 form;
};

// index into the abbrevs table below.
enum
{
Luuk van Dijk's avatar
Luuk van Dijk committed
112 113 114
	DW_ABRV_NULL,
	DW_ABRV_COMPUNIT,
	DW_ABRV_FUNCTION,
Luuk van Dijk's avatar
Luuk van Dijk committed
115 116 117 118 119 120 121 122 123
	DW_NABRV
};

typedef struct DWAbbrev DWAbbrev;
struct DWAbbrev {
	uint8 tag;
	uint8 children;
	DWAttrForm attr[30];
} abbrevs[DW_NABRV] = {
Luuk van Dijk's avatar
Luuk van Dijk committed
124 125
	/* The mandatory DW_ABRV_NULL entry. */
	{ 0 },
Luuk van Dijk's avatar
Luuk van Dijk committed
126 127 128
	/* COMPUNIT */
	{
		DW_TAG_compile_unit, DW_CHILDREN_yes,
Luuk van Dijk's avatar
Luuk van Dijk committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
		DW_AT_name,	 DW_FORM_string,
		DW_AT_language,	 DW_FORM_data1,
		DW_AT_low_pc,	 DW_FORM_addr,
		DW_AT_high_pc,	 DW_FORM_addr,
		DW_AT_stmt_list, DW_FORM_data4,
		0, 0
	},
	/* FUNCTION */
	{
		DW_TAG_subprogram, DW_CHILDREN_no,
		DW_AT_name,	 DW_FORM_string,
		DW_AT_low_pc,	 DW_FORM_addr,
		DW_AT_high_pc,	 DW_FORM_addr,
		0, 0
	},
Luuk van Dijk's avatar
Luuk van Dijk committed
144 145
};

Luuk van Dijk's avatar
Luuk van Dijk committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
static void
writeabbrev(void)
{
	int i, n;

	abbrevo = cpos();
	for (i = 1; i < DW_NABRV; i++) {
		// See section 7.5.3
		uleb128put(i);
		uleb128put(abbrevs[i].tag);
		cput(abbrevs[i].children);
		// 0 is not a valid attr or form, so we can treat this as
		// a string
		n = strlen((char*)abbrevs[i].attr) / 2;
		strnput((char*)abbrevs[i].attr,
			(n+1) * sizeof(DWAttrForm));
	}
	cput(0);
	abbrevsize = cpos() - abbrevo;
}

Luuk van Dijk's avatar
Luuk van Dijk committed
167 168 169 170
/*
 * Debugging Information Entries and their attributes
 */

Luuk van Dijk's avatar
Luuk van Dijk committed
171 172 173
// For DW_CLS_string and _block, value should contain the length, and
// data the data, for all others, value is the whole thing and data is
// null.
Luuk van Dijk's avatar
Luuk van Dijk committed
174 175 176

typedef struct DWAttr DWAttr;
struct DWAttr {
Luuk van Dijk's avatar
Luuk van Dijk committed
177 178 179 180 181
	DWAttr *link;
	uint8 atr;  // DW_AT_
	uint8 cls;  // DW_CLS_
	vlong value;
	char *data;
Luuk van Dijk's avatar
Luuk van Dijk committed
182 183 184 185
};

typedef struct DWDie DWDie;
struct DWDie {
Luuk van Dijk's avatar
Luuk van Dijk committed
186 187 188 189
	int abbrev;
	DWDie *link;
	DWDie *child;
	DWAttr *attr;
Luuk van Dijk's avatar
Luuk van Dijk committed
190 191 192 193 194 195 196 197
};

// top level compilation unit DIE's
static DWDie *dwinfo;

static DWDie*
newdie(DWDie *link, int abbrev)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
198
	DWDie *die;
Luuk van Dijk's avatar
Luuk van Dijk committed
199

Luuk van Dijk's avatar
Luuk van Dijk committed
200 201 202 203
	die = mal(sizeof *die);
	die->abbrev = abbrev;
	die->link = link;
	return die;
Luuk van Dijk's avatar
Luuk van Dijk committed
204 205 206 207 208
}

static DWAttr*
newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
209 210 211 212 213 214 215 216 217 218 219 220
	DWAttr *a;

	a = mal(sizeof *a);
	a->link = die->attr;
	die->attr = a;
	a->atr = attr;
	a->cls = cls;
	a->value = value;
	a->data = data;
	return a;
}

Luuk van Dijk's avatar
Luuk van Dijk committed
221 222 223
static void
putattr(int form, int cls, vlong value, char *data)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	switch(form) {
	case DW_FORM_addr:	// address
		addrput(value);
		break;

	case DW_FORM_block1:	// block
		value &= 0xff;
		cput(value);
		while(value--)
			cput(*data++);
		break;

	case DW_FORM_block2:	// block
		value &= 0xffff;
		WPUT(value);
		while(value--)
			cput(*data++);
		break;

	case DW_FORM_block4:	// block
		value &= 0xffffffff;
		LPUT(value);
		while(value--)
			cput(*data++);
		break;

	case DW_FORM_block:	// block
		uleb128put(value);
		while(value--)
			cput(*data++);
		break;

	case DW_FORM_data1:	// constant
		cput(value);
		break;

	case DW_FORM_data2:	// constant
		WPUT(value);
		break;

Luuk van Dijk's avatar
Luuk van Dijk committed
264
	case DW_FORM_data4:	// constant, {line,loclist,mac,rangelist}ptr
Luuk van Dijk's avatar
Luuk van Dijk committed
265 266 267
		LPUT(value);
		break;

Luuk van Dijk's avatar
Luuk van Dijk committed
268
	case DW_FORM_data8:	// constant, {line,loclist,mac,rangelist}ptr
Luuk van Dijk's avatar
Luuk van Dijk committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
		VPUT(value);
		break;

	case DW_FORM_sdata:	// constant
		sleb128put(value);
		break;

	case DW_FORM_udata:	// constant
		uleb128put(value);
		break;

	case DW_FORM_string:	// string
		strnput(data, value+1);
		break;

	case DW_FORM_flag:	// flag
		cput(value?1:0);
		break;

	case DW_FORM_strp:	// string
	case DW_FORM_ref_addr:	// reference
	case DW_FORM_ref1:	// reference
	case DW_FORM_ref2:	// reference
	case DW_FORM_ref4:	// reference
	case DW_FORM_ref8:	// reference
	case DW_FORM_ref_udata:	// reference
	case DW_FORM_indirect:	// (see Section 7.5.3)
	default:
		diag("Unsupported atribute form %d / class %d", form, cls);
		errorexit();
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
300 301 302 303 304
}

static void
putattrs(int abbrev, DWAttr* attr)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318
	DWAttr *attrs[DW_AT_recursive + 1];
	DWAttrForm* af;

	memset(attrs, 0, sizeof attrs);
	for( ; attr; attr = attr->link)
		attrs[attr->atr] = attr;
	for(af = abbrevs[abbrev].attr; af->attr; af++)
		if (attrs[af->attr])
			putattr(af->form,
				attrs[af->attr]->cls,
				attrs[af->attr]->value,
				attrs[af->attr]->data);
		else
			putattr(af->form, 0, 0, 0);
Luuk van Dijk's avatar
Luuk van Dijk committed
319 320 321 322 323 324 325
}

static void putdie(DWDie* die);

static void
putdies(DWDie* die)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
326 327
	for(; die; die = die->link)
		putdie(die);
Luuk van Dijk's avatar
Luuk van Dijk committed
328 329 330 331 332
}

static void
putdie(DWDie* die)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
333 334 335 336 337 338
	uleb128put(die->abbrev);
	putattrs(die->abbrev, die->attr);
	if (abbrevs[die->abbrev].children) {
		putdies(die->child);
		cput(0);
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
339 340 341 342 343
}

static void
reverselist(DWDie** list)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	DWDie *curr, * prev;

	curr = *list;
	prev = 0;
	while(curr) {
		DWDie* next = curr->link;
		curr->link = prev;
		prev = curr;
		curr = next;
	}
	*list = prev;
}

static void
reversetree(DWDie** list)
{
	 DWDie *die;

	 reverselist(list);
	 if (*list != nil && abbrevs[(*list)->abbrev].children)
		 for (die = *list; die != nil; die = die->link)
			 reversetree(&die->child);
Luuk van Dijk's avatar
Luuk van Dijk committed
366 367 368 369 370 371 372 373 374 375 376 377
}

/*
 * Filename fragments for the line history stack.
 */

static char **ftab;
static int ftabsize;

void
dwarfaddfrag(int n, char *frag)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
378
	int s;
Luuk van Dijk's avatar
Luuk van Dijk committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395

	if (n >= ftabsize) {
		s = ftabsize;
		ftabsize = 1 + n + (n >> 2);
		ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
		memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
	}

	if (*frag == '<')
		frag++;
	ftab[n] = frag;
}

// Returns a malloc'ed string, piecewise copied from the ftab.
static char *
decodez(char *s)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
396 397 398
	int len, o;
	char *ss, *f;
	char *r, *rb, *re;
Luuk van Dijk's avatar
Luuk van Dijk committed
399 400 401

	len = 0;
	ss = s + 1;	// first is 0
Luuk van Dijk's avatar
Luuk van Dijk committed
402
	while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
Luuk van Dijk's avatar
Luuk van Dijk committed
403 404 405 406 407
		if (o < 0 || o >= ftabsize) {
			diag("corrupt z entry");
			return 0;
		}
		f = ftab[o];
Luuk van Dijk's avatar
Luuk van Dijk committed
408
		if (f == nil) {
Luuk van Dijk's avatar
Luuk van Dijk committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
			diag("corrupt z entry");
			return 0;
		}
		len += strlen(f) + 1;	// for the '/'
		ss += 2;
	}

	if (len == 0)
		return 0;

	r = malloc(len + 1);
	rb = r;
	re = rb + len + 1;

	s++;
	while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) {
		f = ftab[o];
		if (rb == r || rb[-1] == '/')
			rb = seprint(rb, re, "%s", f);
		else
			rb = seprint(rb, re, "/%s", f);
		s += 2;
	}
	return r;
}

/*
 * The line history itself
 */

439
static char **histfile;	   // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0.
Luuk van Dijk's avatar
Luuk van Dijk committed
440 441 442 443 444 445
static int  histfilesize;
static int  histfilecap;

static void
clearhistfile(void)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
446
	int i;
Luuk van Dijk's avatar
Luuk van Dijk committed
447

448
	// [0] holds "<eof>"
Luuk van Dijk's avatar
Luuk van Dijk committed
449 450 451
	for (i = 1; i < histfilesize; i++)
		free(histfile[i]);
	histfilesize = 0;
Luuk van Dijk's avatar
Luuk van Dijk committed
452 453 454 455 456
}

static int
addhistfile(char *zentry)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
	char *fname;

	if (histfilesize == histfilecap) {
		histfilecap = 2 * histfilecap + 2;
		histfile = realloc(histfile, histfilecap * sizeof(char*));
	}
	if (histfilesize == 0)
		histfile[histfilesize++] = "<eof>";

	fname = decodez(zentry);
	if (fname == 0)
		return -1;
	// Don't fill with duplicates (check only top one).
	if (strcmp(fname, histfile[histfilesize-1]) == 0) {
		free(fname);
		return histfilesize - 1;
	}
	histfile[histfilesize++] = fname;
	return histfilesize - 1;
Luuk van Dijk's avatar
Luuk van Dijk committed
476 477 478 479 480
}

// Go's runtime C sources are sane, and Go sources nest only 1 level,
// so 16 should be plenty.
static struct {
Luuk van Dijk's avatar
Luuk van Dijk committed
481 482
	int file;
	vlong line;
Luuk van Dijk's avatar
Luuk van Dijk committed
483 484 485 486 487 488
} includestack[16];
static int includetop;
static vlong absline;

typedef struct Linehist Linehist;
struct Linehist {
Luuk van Dijk's avatar
Luuk van Dijk committed
489 490 491 492
	Linehist *link;
	vlong absline;
	vlong line;
	int file;
Luuk van Dijk's avatar
Luuk van Dijk committed
493 494 495 496 497 498 499
};

static Linehist *linehist;

static void
checknesting(void)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
500 501 502 503 504 505 506 507 508 509 510 511
	int i;

	if (includetop < 0) {
		diag("corrupt z stack");
		errorexit();
	}
	if (includetop >= nelem(includestack)) {
		diag("nesting too deep");
		for (i = 0; i < nelem(includestack); i++)
			diag("\t%s", histfile[includestack[i].file]);
		errorexit();
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
512 513 514 515 516 517
}

/* find z and Z entries in the Auto list (of a Prog), and reset the history stack */
static char *
inithist(Auto *a)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
518 519
	char *unitname;
	Linehist *lh;
Luuk van Dijk's avatar
Luuk van Dijk committed
520 521 522

	for (; a; a = a->link)
		if (a->type == D_FILE)
Luuk van Dijk's avatar
Luuk van Dijk committed
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
			break;
	if (a==nil)
		return 0;

	// We have a new history.  They are guaranteed to come completely
	// at the beginning of the compilation unit.
	if (a->aoffset != 1) {
		diag("stray 'z' with offset %d", a->aoffset);
		return 0;
	}

	unitname = decodez(a->asym->name);

	// Clear the history.
	clearhistfile();
	includetop = 0;
	includestack[includetop].file = 0;
	includestack[includetop].line = -1;
	absline = 0;
	while (linehist != nil) {
		lh = linehist->link;
		free(linehist);
		linehist = lh;
	}

	// Construct the new one.
	for (; a; a = a->link) {
		if (a->type == D_FILE) {  // 'z'
			int f = addhistfile(a->asym->name);
			if (f < 0) {	   // pop file
				includetop--;
				checknesting();
			} else if(f != includestack[includetop].file) { // pushed a new file
				includestack[includetop].line += a->aoffset - absline;
				includetop++;
				checknesting();
				includestack[includetop].file = f;
				includestack[includetop].line = 1;

			}
			absline = a->aoffset;
		} else if (a->type == D_FILE1) {  // 'Z'
			// We could just fixup the current
			// linehist->line, but there doesn't appear to
			// be a guarantee that every 'Z' is preceded
			// by it's own 'z', so do the safe thing and
			// update the stack and push a new Linehist
			// entry
			includestack[includetop].line =	 a->aoffset;
		} else
			continue;
		if (linehist == 0 || linehist->absline != absline) {
			Linehist* lh = malloc(sizeof *lh);
			lh->link = linehist;
			lh->absline = absline;
			linehist = lh;
		}
		linehist->file = includestack[includetop].file;
		linehist->line = includestack[includetop].line;
	}
	return unitname;
Luuk van Dijk's avatar
Luuk van Dijk committed
584 585 586 587 588
}

static Linehist *
searchhist(vlong absline)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
589
	Linehist *lh;
Luuk van Dijk's avatar
Luuk van Dijk committed
590

Luuk van Dijk's avatar
Luuk van Dijk committed
591 592 593 594
	for (lh = linehist; lh; lh = lh->link)
		if (lh->absline <= absline)
			break;
	return lh;
Luuk van Dijk's avatar
Luuk van Dijk committed
595 596 597 598 599
}

static int
guesslang(char *s)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
600 601
	if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0)
		return DW_LANG_Go;
Luuk van Dijk's avatar
Luuk van Dijk committed
602

Luuk van Dijk's avatar
Luuk van Dijk committed
603
	return DW_LANG_C;
Luuk van Dijk's avatar
Luuk van Dijk committed
604 605 606 607 608 609 610 611
}

/*
 * Generate short opcodes when possible, long ones when neccesary.
 * See section 6.2.5
 */

enum {
Luuk van Dijk's avatar
Luuk van Dijk committed
612 613 614
	LINE_BASE = -1,
	LINE_RANGE = 4,
	OPCODE_BASE = 5
Luuk van Dijk's avatar
Luuk van Dijk committed
615 616 617 618 619
};

static void
putpclcdelta(vlong delta_pc, vlong delta_lc)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
620 621 622 623 624 625 626 627 628
	if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
		vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
		if (OPCODE_BASE <= opcode && opcode < 256) {
			cput(opcode);
			return;
		}
	}

	if (delta_pc) {
Luuk van Dijk's avatar
Luuk van Dijk committed
629 630
		cput(DW_LNS_advance_pc);
		sleb128put(delta_pc);
Luuk van Dijk's avatar
Luuk van Dijk committed
631 632 633 634 635
	}

	cput(DW_LNS_advance_line);
	sleb128put(delta_lc);
	cput(DW_LNS_copy);
Luuk van Dijk's avatar
Luuk van Dijk committed
636 637 638 639 640 641 642 643 644 645 646
}


/*
 * Walk prog table, emit line program and build DIE tree.
 */

// flush previous compilation unit.
static void
flushunit(vlong pc, vlong unitstart)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
647 648
	vlong here;

Luuk van Dijk's avatar
Luuk van Dijk committed
649 650
	if (dwinfo != nil && pc != 0) {
		newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
Luuk van Dijk's avatar
Luuk van Dijk committed
651 652 653 654 655 656 657 658 659 660 661 662 663 664
	}

	if (unitstart >= 0) {
		cput(0);  // start extended opcode
		uleb128put(1);
		cput(DW_LNE_end_sequence);
		cflush();

		here = cpos();
		seek(cout, unitstart, 0);
		LPUT(here - unitstart - sizeof(int32));
		cflush();
		seek(cout, here, 0);
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
665 666 667 668 669
}

static void
writelines(void)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
670 671 672 673
	Prog *p, *q;
	Sym *s;
	char *unitname;
	vlong unitstart;
Luuk van Dijk's avatar
Luuk van Dijk committed
674
	vlong pc, epc, lc, llc, lline;
Luuk van Dijk's avatar
Luuk van Dijk committed
675 676 677 678
	int currfile;
	int i;
	Linehist *lh;

Luuk van Dijk's avatar
Luuk van Dijk committed
679
	q = nil;
Luuk van Dijk's avatar
Luuk van Dijk committed
680
	unitstart = -1;
Luuk van Dijk's avatar
Luuk van Dijk committed
681
	epc = pc = 0;
Luuk van Dijk's avatar
Luuk van Dijk committed
682 683 684 685 686 687
	lc = 1;
	llc = 1;
	currfile = -1;
	lineo = cpos();

	for (p = textp; p != P; p = p->pcond) {
Luuk van Dijk's avatar
Luuk van Dijk committed
688 689
		curtext = p; // for diag

Luuk van Dijk's avatar
Luuk van Dijk committed
690 691
		s = p->from.sym;
		if (s == nil || s->type != STEXT) {
Luuk van Dijk's avatar
Luuk van Dijk committed
692 693 694 695 696 697 698
			diag("->pcond was supposed to loop over STEXT: %P", p);
			continue;
		}

		// Look for history stack.  If we find one,
		// we're entering a new compilation unit
		if ((unitname = inithist(p->to.autom)) != 0) {
Luuk van Dijk's avatar
Luuk van Dijk committed
699
			flushunit(epc, unitstart);
Luuk van Dijk's avatar
Luuk van Dijk committed
700 701 702 703 704 705 706 707 708 709 710
			unitstart = cpos();
			if(debug['v'] > 1) {
				print("dwarf writelines found %s\n", unitname);
				Linehist* lh;
				for (lh = linehist; lh; lh = lh->link)
					print("\t%8lld: [%4lld]%s\n",
					      lh->absline, lh->line, histfile[lh->file]);
			}
			dwinfo = newdie(dwinfo, DW_ABRV_COMPUNIT);
			newattr(dwinfo, DW_AT_name, DW_CLS_STRING, strlen(unitname), unitname);
			newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, guesslang(unitname), 0);
Luuk van Dijk's avatar
Luuk van Dijk committed
711 712
			newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
			newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, p->pc, 0);
Luuk van Dijk's avatar
Luuk van Dijk committed
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
			// Write .debug_line Line Number Program Header (sec 6.2.4)
			// Fields marked with (*) must be changed for 64-bit dwarf
			LPUT(0);   // unit_length (*), will be filled in later.
			WPUT(3);   // version
			LPUT(11);  // header_length (*)
			cput(1);   // minimum_instruction_length
			cput(1);   // default_is_stmt
			cput(LINE_BASE);     // line_base
			cput(LINE_RANGE);    // line_range
			cput(OPCODE_BASE);   // opcode_base (we only use 1..4)
			cput(0);   // standard_opcode_lengths[1]
			cput(1);   // standard_opcode_lengths[2]
			cput(1);   // standard_opcode_lengths[3]
			cput(1);   // standard_opcode_lengths[4]
			cput(0);   // include_directories  (empty)
			cput(0);   // file_names (empty) (emitted by DW_LNE's below)
			for (i=1; i < histfilesize; i++) {
				cput(0);  // start extended opcode
				uleb128put(1 + strlen(histfile[i]) + 4);
				cput(DW_LNE_define_file);
				strnput(histfile[i], strlen(histfile[i]) + 4);
				// 4 zeros: the string termination + 3 fields.
			}

Luuk van Dijk's avatar
Luuk van Dijk committed
737
			epc = pc = p->pc;
Luuk van Dijk's avatar
Luuk van Dijk committed
738 739 740 741 742 743 744 745 746
			currfile = 1;
			lc = 1;
			llc = 1;

			cput(0);  // start extended opcode
			uleb128put(1 + PtrSize);
			cput(DW_LNE_set_address);
			addrput(pc);
		}
Luuk van Dijk's avatar
Luuk van Dijk committed
747
		if (!s->reachable)
Luuk van Dijk's avatar
Luuk van Dijk committed
748 749 750 751 752 753 754 755 756 757 758
			continue;
		if (unitstart < 0) {
			diag("reachable code before seeing any history: %P", p);
			continue;
		}

		dwinfo->child = newdie(dwinfo->child, DW_ABRV_FUNCTION);
		newattr(dwinfo->child, DW_AT_name, DW_CLS_STRING, strlen(s->name), s->name);
		newattr(dwinfo->child, DW_AT_low_pc, DW_CLS_ADDRESS, p->pc, 0);

		for(q = p; q != P && (q == p || q->as != ATEXT); q = q->link) {
759
			epc = q->pc;
Luuk van Dijk's avatar
Luuk van Dijk committed
760 761 762 763 764
			lh = searchhist(q->line);
			if (lh == nil) {
				diag("corrupt history or bad absolute line: %P", q);
				continue;
			}
765
			if (lh->file < 1) {  // 0 is the past-EOF entry.
766
				//diag("instruction with linenumber past EOF in %s: %P", unitname, q);
767 768 769
				continue;
			}

Luuk van Dijk's avatar
Luuk van Dijk committed
770 771 772
			lline = lh->line + q->line - lh->absline;
			if (debug['v'] > 1)
				print("%6llux %s[%lld] %P\n", q->pc, histfile[lh->file], lline, q);
Luuk van Dijk's avatar
Luuk van Dijk committed
773

Luuk van Dijk's avatar
Luuk van Dijk committed
774 775 776 777 778 779 780 781 782 783 784 785
			if (q->line == lc)
				continue;
			if (currfile != lh->file) {
				currfile = lh->file;
				cput(DW_LNS_set_file);
				uleb128put(currfile);
			}
			putpclcdelta(q->pc - pc, lline - llc);
			pc  = q->pc;
			lc  = q->line;
			llc = lline;
		}
Luuk van Dijk's avatar
Luuk van Dijk committed
786 787 788

		newattr(dwinfo->child, DW_AT_high_pc, DW_CLS_ADDRESS, epc+1, 0);

Luuk van Dijk's avatar
Luuk van Dijk committed
789
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
790 791

	flushunit(epc, unitstart);
Luuk van Dijk's avatar
Luuk van Dijk committed
792
	linesize = cpos() - lineo;
Luuk van Dijk's avatar
Luuk van Dijk committed
793 794
}

Luuk van Dijk's avatar
Luuk van Dijk committed
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
/*
 *  Emit .debug_frame
 */
enum
{
	CIERESERVE = 16,
	DATAALIGNMENTFACTOR = -4,
	FAKERETURNCOLUMN = 16
};

static void
putpccfadelta(vlong deltapc, vlong cfa)
{
	if (deltapc < 0x40) {
		cput(DW_CFA_advance_loc + deltapc);
	} else if (deltapc < 0x100) {
		cput(DW_CFA_advance_loc1);
		cput(deltapc);
	} else if (deltapc < 0x10000) {
		cput(DW_CFA_advance_loc2);
		WPUT(deltapc);
	} else {
		cput(DW_CFA_advance_loc4);
		LPUT(deltapc);
	}

	cput(DW_CFA_def_cfa_offset_sf);
	sleb128put(cfa / DATAALIGNMENTFACTOR);
}

static void
writeframes(void)
{
	Prog *p, *q;
	Sym *s;
	vlong fdeo, fdesize, pad, cfa, pc, epc;

	frameo = cpos();

	// Emit the CIE, Section 6.4.1
	LPUT(CIERESERVE);  // initial length, must be multiple of PtrSize
	LPUT(0xffffffff);  // cid.
	cput(3);	// dwarf version
	cput(0);	// augmentation ""
	uleb128put(1);	// code_alignment_factor
	sleb128put(DATAALIGNMENTFACTOR); // guess
	uleb128put(FAKERETURNCOLUMN); // return_address_register

	cput(DW_CFA_def_cfa);
	uleb128put(DWARFREGSP);	// register SP (**ABI-dependent, defined in l.h)
	uleb128put(PtrSize);	// offset

	cput(DW_CFA_offset + FAKERETURNCOLUMN);	 // return address
	uleb128put(-PtrSize / DATAALIGNMENTFACTOR);	// at cfa - x*4

	// 4 is to exclude the length field.
	pad = CIERESERVE + frameo + 4 - cpos();
	if (pad < 0) {
		diag("CIERESERVE too small by %lld bytes.", -pad);
		errorexit();
	}
	strnput("", pad);

	for (p = textp; p != P; p = p->pcond) {
		curtext = p; // for diag
		s = p->from.sym;
		if (s == nil || s->type != STEXT) {
			diag("->pcond was supposed to loop over STEXT: %P", p);
			continue;
		}
		if (!s->reachable)
			continue;

		fdeo = cpos();
		// Emit a FDE, Section 6.4.1, starting wit a placeholder.
		LPUT(0);	// length, must be multiple of PtrSize
		LPUT(0);	// Pointer to the CIE above, at offset 0
		addrput(0);	// initial location
		addrput(0);	// address range

		cfa = PtrSize;	// CFA starts at sp+PtrSize
		pc = p->pc;
		epc = p->pc;

		for(q = p; q != P && (q == p || q->as != ATEXT); q = q->link) {
			epc = q->pc;
			if (q->spadj == 0)
				continue;

			cfa += q->spadj;
			putpccfadelta(q->pc - pc, cfa);
			pc = q->pc;
		}

		fdesize = cpos() - fdeo - 4;	// exclude the length field.
		pad = rnd(fdesize, PtrSize) - fdesize;
		strnput("", pad);
		fdesize += pad;
		cflush();

		// Emit the FDE header for real, Section 6.4.1.
		seek(cout, fdeo, 0);
		LPUT(fdesize);
		LPUT(0);
		addrput(p->pc);
		addrput(epc - p->pc);

		cflush();
		seek(cout, fdeo + 4 + fdesize, 0);
	}

	cflush();
	framesize = cpos() - frameo;
}

Luuk van Dijk's avatar
Luuk van Dijk committed
910 911 912 913 914 915
/*
 *  Walk DWarfDebugInfoEntries, and emit .debug_info
 */
static void
writeinfo(void)
{
Luuk van Dijk's avatar
Luuk van Dijk committed
916 917
	DWDie *compunit;
	vlong unitstart;
Luuk van Dijk's avatar
Luuk van Dijk committed
918

Luuk van Dijk's avatar
Luuk van Dijk committed
919
	reversetree(&dwinfo);
Luuk van Dijk's avatar
Luuk van Dijk committed
920

Luuk van Dijk's avatar
Luuk van Dijk committed
921
	infoo = cpos();
Luuk van Dijk's avatar
Luuk van Dijk committed
922

Luuk van Dijk's avatar
Luuk van Dijk committed
923 924
	for (compunit = dwinfo; compunit; compunit = compunit->link) {
		unitstart = cpos();
Luuk van Dijk's avatar
Luuk van Dijk committed
925

Luuk van Dijk's avatar
Luuk van Dijk committed
926 927 928 929 930 931
		// Write .debug_info Compilation Unit Header (sec 7.5.1)
		// Fields marked with (*) must be changed for 64-bit dwarf
		LPUT(0);   // unit_length (*), will be filled in later.
		WPUT(3);   // version
		LPUT(0);   // debug_abbrev_offset (*)
		cput(PtrSize);	 // address_size
Luuk van Dijk's avatar
Luuk van Dijk committed
932

Luuk van Dijk's avatar
Luuk van Dijk committed
933
		putdie(compunit);
Luuk van Dijk's avatar
Luuk van Dijk committed
934

Luuk van Dijk's avatar
Luuk van Dijk committed
935 936 937 938 939 940 941
		cflush();
		vlong here = cpos();
		seek(cout, unitstart, 0);
		LPUT(here - unitstart - sizeof(int32));
		cflush();
		seek(cout, here, 0);
	}
Luuk van Dijk's avatar
Luuk van Dijk committed
942

Luuk van Dijk's avatar
Luuk van Dijk committed
943 944
	cflush();
	infosize = cpos() - infoo;
Luuk van Dijk's avatar
Luuk van Dijk committed
945 946
}

Luuk van Dijk's avatar
Luuk van Dijk committed
947 948 949 950 951 952 953 954 955
void
dwarfemitdebugsections(void)
{
	writeabbrev();
	writelines();
	writeframes();
	writeinfo();
}

Luuk van Dijk's avatar
Luuk van Dijk committed
956
/*
Luuk van Dijk's avatar
Luuk van Dijk committed
957
 *  Elf.
Luuk van Dijk's avatar
Luuk van Dijk committed
958
 */
Luuk van Dijk's avatar
Luuk van Dijk committed
959 960
enum
{
Luuk van Dijk's avatar
Luuk van Dijk committed
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
	ElfStrDebugAbbrev,
	ElfStrDebugAranges,
	ElfStrDebugFrame,
	ElfStrDebugInfo,
	ElfStrDebugLine,
	ElfStrDebugLoc,
	ElfStrDebugMacinfo,
	ElfStrDebugPubNames,
	ElfStrDebugPubTypes,
	ElfStrDebugRanges,
	ElfStrDebugStr,
	NElfStrDbg
};

vlong elfstrdbg[NElfStrDbg];

void
Russ Cox's avatar
Russ Cox committed
978
dwarfaddshstrings(Sym *shstrtab)
Luuk van Dijk's avatar
Luuk van Dijk committed
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
{
	elfstrdbg[ElfStrDebugAbbrev]   = addstring(shstrtab, ".debug_abbrev");
	elfstrdbg[ElfStrDebugAranges]  = addstring(shstrtab, ".debug_aranges");
	elfstrdbg[ElfStrDebugFrame]    = addstring(shstrtab, ".debug_frame");
	elfstrdbg[ElfStrDebugInfo]     = addstring(shstrtab, ".debug_info");
	elfstrdbg[ElfStrDebugLine]     = addstring(shstrtab, ".debug_line");
	elfstrdbg[ElfStrDebugLoc]      = addstring(shstrtab, ".debug_loc");
	elfstrdbg[ElfStrDebugMacinfo]  = addstring(shstrtab, ".debug_macinfo");
	elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
	elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
	elfstrdbg[ElfStrDebugRanges]   = addstring(shstrtab, ".debug_ranges");
	elfstrdbg[ElfStrDebugStr]      = addstring(shstrtab, ".debug_str");
}

void
Luuk van Dijk's avatar
Luuk van Dijk committed
994
dwarfaddelfheaders(void)
Luuk van Dijk's avatar
Luuk van Dijk committed
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
{
	ElfShdr *sh;

	sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
	sh->type = SHT_PROGBITS;
	sh->off = abbrevo;
	sh->size = abbrevsize;
	sh->addralign = 1;

	sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
	sh->type = SHT_PROGBITS;
	sh->off = lineo;
	sh->size = linesize;
	sh->addralign = 1;

Luuk van Dijk's avatar
Luuk van Dijk committed
1010 1011 1012 1013 1014 1015
	sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
	sh->type = SHT_PROGBITS;
	sh->off = frameo;
	sh->size = framesize;
	sh->addralign = 1;

Luuk van Dijk's avatar
Luuk van Dijk committed
1016 1017 1018 1019 1020 1021
	sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
	sh->type = SHT_PROGBITS;
	sh->off = infoo;
	sh->size = infosize;
	sh->addralign = 1;
}
Luuk van Dijk's avatar
Luuk van Dijk committed
1022

Luuk van Dijk's avatar
Luuk van Dijk committed
1023 1024 1025
/*
 * Macho
 */
Luuk van Dijk's avatar
Luuk van Dijk committed
1026 1027 1028 1029 1030 1031 1032 1033
void
dwarfaddmachoheaders(void)
{
	MachoSect *msect;
	MachoSeg *ms;

	vlong fakestart;

Russ Cox's avatar
tabs  
Russ Cox committed
1034 1035
	// Zero vsize segments won't be loaded in memory, even so they
	// have to be page aligned in the file.
Luuk van Dijk's avatar
Luuk van Dijk committed
1036 1037
	fakestart = abbrevo & ~0xfff;

Ken Thompson's avatar
Ken Thompson committed
1038
	ms = newMachoSeg("__DWARF", 4);
Luuk van Dijk's avatar
Luuk van Dijk committed
1039
	ms->fileoffset = fakestart;
Luuk van Dijk's avatar
Luuk van Dijk committed
1040
	ms->filesize = abbrevo-fakestart + abbrevsize+linesize+framesize+infosize;
Luuk van Dijk's avatar
Luuk van Dijk committed
1041 1042 1043 1044 1045 1046 1047 1048 1049

	msect = newMachoSect(ms, "__debug_abbrev");
	msect->off = abbrevo;
	msect->size = abbrevsize;

	msect = newMachoSect(ms, "__debug_line");
	msect->off = lineo;
	msect->size = linesize;

Luuk van Dijk's avatar
Luuk van Dijk committed
1050 1051 1052 1053
	msect = newMachoSect(ms, "__debug_frame");
	msect->off = frameo;
	msect->size = framesize;

Luuk van Dijk's avatar
Luuk van Dijk committed
1054 1055 1056 1057
	msect = newMachoSect(ms, "__debug_info");
	msect->off = infoo;
	msect->size = infosize;
}