mirror of
https://github.com/golang/go
synced 2024-11-12 09:20:22 -07:00
code coverage tool
$ 6cov -g 235.go 6.out 235.go:62,62 main·main 0x27c9-0x2829 MOVL $main·.stringo(SB),AX 235.go:30,30 main·main 0x2856-0x285e ADDQ $6c0,SP $ and assorted fixes. R=r DELTA=743 (732 added, 8 deleted, 3 changed) OCL=19226 CL=19243
This commit is contained in:
parent
2355395550
commit
7832ab5ba0
28
src/cmd/cov/Makefile
Normal file
28
src/cmd/cov/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
# Copyright 2009 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.
|
||||
|
||||
include ../../Make.conf
|
||||
|
||||
# The directory is cov because the source is portable and general.
|
||||
# We call the binary 6cov to avoid confusion and because this binary
|
||||
# is linked only with amd64 and x86 support.
|
||||
|
||||
TARG=6cov
|
||||
OFILES=\
|
||||
main.$O\
|
||||
tree.$O\
|
||||
|
||||
HFILES=\
|
||||
tree.h\
|
||||
|
||||
$(TARG): $(OFILES)
|
||||
$(LD) -o $(TARG) -L$(GOROOT)/lib $(OFILES) -lmach_amd64 -lregexp9 -lbio -l9
|
||||
|
||||
clean:
|
||||
rm -f $(OFILES) $(TARG)
|
||||
|
||||
install: $(TARG)
|
||||
cp $(TARG) $(BIN)/$(TARG)
|
||||
|
||||
$(OFILES): $(HFILES)
|
385
src/cmd/cov/main.c
Normal file
385
src/cmd/cov/main.c
Normal file
@ -0,0 +1,385 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
/*
|
||||
* code coverage
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <time.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <ctype.h>
|
||||
#include <regexp9.h>
|
||||
#include "tree.h"
|
||||
|
||||
#include <ureg_amd64.h>
|
||||
#include <mach_amd64.h>
|
||||
typedef struct Ureg Ureg;
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: cov 6.out [-lv] [-g regexp] [args...]\n");
|
||||
fprint(2, "-g specifies pattern of interesting functions or files\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
typedef struct Range Range;
|
||||
struct Range
|
||||
{
|
||||
uvlong pc;
|
||||
uvlong epc;
|
||||
};
|
||||
|
||||
int chatty;
|
||||
int fd;
|
||||
int longnames;
|
||||
int pid;
|
||||
Map *mem;
|
||||
Map *text;
|
||||
Fhdr fhdr;
|
||||
Reprog *grep;
|
||||
char cwd[1000];
|
||||
int ncwd;
|
||||
|
||||
Tree breakpoints; // code ranges not run
|
||||
|
||||
/*
|
||||
* comparison for Range structures
|
||||
* they are "equal" if they overlap, so
|
||||
* that a search for [pc, pc+1) finds the
|
||||
* Range containing pc.
|
||||
*/
|
||||
int
|
||||
rangecmp(void *va, void *vb)
|
||||
{
|
||||
Range *a = va, *b = vb;
|
||||
if(a->epc <= b->pc)
|
||||
return 1;
|
||||
if(b->epc <= a->pc)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* remember that we ran the section of code [pc, epc).
|
||||
*/
|
||||
void
|
||||
ran(uvlong pc, uvlong epc)
|
||||
{
|
||||
Range key;
|
||||
Range *r;
|
||||
uvlong oldepc;
|
||||
|
||||
if(chatty)
|
||||
print("run %#llux-%#llux\n", pc, epc);
|
||||
|
||||
key.pc = pc;
|
||||
key.epc = pc+1;
|
||||
r = treeget(&breakpoints, &key);
|
||||
if(r == nil)
|
||||
sysfatal("unchecked breakpoint at %#lux+%d", pc, (int)(epc-pc));
|
||||
|
||||
// Might be that the tail of the sequence
|
||||
// was run already, so r->epc is before the end.
|
||||
// Adjust len.
|
||||
if(epc > r->epc)
|
||||
epc = r->epc;
|
||||
|
||||
if(r->pc == pc) {
|
||||
r->pc = epc;
|
||||
} else {
|
||||
// Chop r to before pc;
|
||||
// add new entry for after if needed.
|
||||
// Changing r->epc does not affect r's position in the tree.
|
||||
oldepc = r->epc;
|
||||
r->epc = pc;
|
||||
if(epc < oldepc) {
|
||||
Range *n;
|
||||
n = malloc(sizeof *n);
|
||||
n->pc = epc;
|
||||
n->epc = oldepc;
|
||||
treeput(&breakpoints, n, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if s is in the current directory or below,
|
||||
* return the relative path.
|
||||
*/
|
||||
char*
|
||||
shortname(char *s)
|
||||
{
|
||||
if(!longnames && strlen(s) > ncwd && memcmp(s, cwd, ncwd) == 0 && s[ncwd] == '/')
|
||||
return s+ncwd+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* we've decided that [pc, epc) did not run.
|
||||
* do something about it.
|
||||
*/
|
||||
void
|
||||
missing(uvlong pc, uvlong epc)
|
||||
{
|
||||
char src1[1000];
|
||||
char src2[1000];
|
||||
char buf[100];
|
||||
Symbol s;
|
||||
char *p;
|
||||
|
||||
if(!findsym(pc, CTEXT, &s) || !fileline(src1, sizeof src1, pc) || !fileline(src2, sizeof src2, pc)) {
|
||||
print("%#llux-%#llux\n", pc, epc);
|
||||
return;
|
||||
}
|
||||
|
||||
if(pc == s.value) {
|
||||
// never entered function
|
||||
print("%s %s never called (%#llux-%#llux)\n", shortname(src1), s.name, pc, epc);
|
||||
return;
|
||||
}
|
||||
if(pc <= s.value+13) {
|
||||
// probably stub for stack growth.
|
||||
// check whether last instruction is call to morestack.
|
||||
// the -5 below is the length of
|
||||
// CALL sys.morestack.
|
||||
buf[0] = 0;
|
||||
machdata->das(text, epc-5, 0, buf, sizeof buf);
|
||||
if(strstr(buf, "morestack"))
|
||||
return;
|
||||
}
|
||||
|
||||
if(epc - pc == 5) {
|
||||
// check for CALL sys.throwindex
|
||||
buf[0] = 0;
|
||||
machdata->das(text, pc, 0, buf, sizeof buf);
|
||||
if(strstr(buf, "throwindex"))
|
||||
return;
|
||||
}
|
||||
|
||||
// show first instruction to make clear where we were.
|
||||
machdata->das(text, pc, 0, buf, sizeof buf);
|
||||
|
||||
// cut filename off src2, leaving just line number.
|
||||
p = strrchr(src2, ':');
|
||||
if(p != nil)
|
||||
p++;
|
||||
else
|
||||
p = src2;
|
||||
print("%s,%s %s %#llux-%#llux %s\n", shortname(src1), p, s.name, pc, epc, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* walk the tree, calling missing for each non-empty
|
||||
* section of missing code.
|
||||
*/
|
||||
void
|
||||
walktree(TreeNode *t)
|
||||
{
|
||||
Range *n;
|
||||
|
||||
if(t == nil)
|
||||
return;
|
||||
walktree(t->left);
|
||||
n = t->key;
|
||||
if(n->pc < n->epc)
|
||||
missing(n->pc, n->epc);
|
||||
walktree(t->right);
|
||||
}
|
||||
|
||||
/*
|
||||
* set a breakpoint all over [pc, epc)
|
||||
* and remember that we did.
|
||||
*/
|
||||
void
|
||||
breakpoint(uvlong pc, uvlong epc)
|
||||
{
|
||||
Range *r;
|
||||
|
||||
r = malloc(sizeof *r);
|
||||
r->pc = pc;
|
||||
r->epc = epc;
|
||||
treeput(&breakpoints, r, r);
|
||||
|
||||
for(; pc < epc; pc+=machdata->bpsize)
|
||||
put1(mem, pc, machdata->bpinst, machdata->bpsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* install breakpoints over all text symbols
|
||||
* that match the pattern.
|
||||
*/
|
||||
void
|
||||
cover(void)
|
||||
{
|
||||
Symbol s;
|
||||
char *lastfn;
|
||||
uvlong lastpc;
|
||||
int i;
|
||||
char buf[200];
|
||||
|
||||
lastfn = nil;
|
||||
lastpc = 0;
|
||||
for(i=0; textsym(&s, i); i++) {
|
||||
switch(s.type) {
|
||||
case 'T':
|
||||
case 't':
|
||||
if(lastpc != 0) {
|
||||
breakpoint(lastpc, s.value);
|
||||
lastpc = 0;
|
||||
}
|
||||
// Ignore second entry for a given name;
|
||||
// that's the debugging blob.
|
||||
if(lastfn && strcmp(s.name, lastfn) == 0)
|
||||
break;
|
||||
lastfn = s.name;
|
||||
buf[0] = 0;
|
||||
fileline(buf, sizeof buf, s.value);
|
||||
if(grep == nil || regexec9(grep, buf, nil, 0) > 0 || regexec9(grep, s.name, nil, 0) > 0)
|
||||
lastpc = s.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uvlong
|
||||
rgetzero(Map *map, char *reg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* remove the breakpoints at pc and successive instructions,
|
||||
* up to and including the first jump or other control flow transfer.
|
||||
*/
|
||||
void
|
||||
uncover(uvlong pc)
|
||||
{
|
||||
uchar buf[1000];
|
||||
int n, n1, n2;
|
||||
uvlong foll[2];
|
||||
|
||||
// Double-check that we stopped at a breakpoint.
|
||||
if(get1(mem, pc, buf, machdata->bpsize) < 0)
|
||||
sysfatal("read mem inst at %#llux: %r", pc);
|
||||
if(memcmp(buf, machdata->bpinst, machdata->bpsize) != 0)
|
||||
sysfatal("stopped at %#llux; not at breakpoint %d", pc, machdata->bpsize);
|
||||
|
||||
// Figure out how many bytes of straight-line code
|
||||
// there are in the text starting at pc.
|
||||
n = 0;
|
||||
while(n < sizeof buf) {
|
||||
n1 = machdata->instsize(text, pc+n);
|
||||
if(n+n1 > sizeof buf)
|
||||
break;
|
||||
n2 = machdata->foll(text, pc+n, rgetzero, foll);
|
||||
n += n1;
|
||||
if(n2 != 1 || foll[0] != pc+n)
|
||||
break;
|
||||
}
|
||||
|
||||
// Record that this section of code ran.
|
||||
ran(pc, pc+n);
|
||||
|
||||
// Put original instructions back.
|
||||
if(get1(text, pc, buf, n) < 0)
|
||||
sysfatal("get1: %r");
|
||||
if(put1(mem, pc, buf, n) < 0)
|
||||
sysfatal("put1: %r");
|
||||
}
|
||||
|
||||
int
|
||||
startprocess(char **argv)
|
||||
{
|
||||
int pid;
|
||||
|
||||
if((pid = fork()) < 0)
|
||||
sysfatal("fork: %r");
|
||||
if(pid == 0) {
|
||||
pid = getpid();
|
||||
if(ctlproc(pid, "hang") < 0)
|
||||
sysfatal("ctlproc hang: %r");
|
||||
execv(argv[0], argv);
|
||||
sysfatal("exec %s: %r", argv[0]);
|
||||
}
|
||||
if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0)
|
||||
sysfatal("attach %d %s: %r", pid, argv[0]);
|
||||
return pid;
|
||||
}
|
||||
|
||||
int
|
||||
go(void)
|
||||
{
|
||||
uvlong pc;
|
||||
char buf[100];
|
||||
int n;
|
||||
|
||||
for(n = 0;; n++) {
|
||||
ctlproc(pid, "startstop");
|
||||
if(get8(mem, offsetof(Ureg, ip), &pc) < 0) {
|
||||
rerrstr(buf, sizeof buf);
|
||||
if(strstr(buf, "exited") || strstr(buf, "No such process"))
|
||||
return n;
|
||||
sysfatal("cannot read pc: %r");
|
||||
}
|
||||
pc--;
|
||||
if(put8(mem, offsetof(Ureg, ip), pc) < 0)
|
||||
sysfatal("cannot write pc: %r");
|
||||
uncover(pc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int n;
|
||||
char *regexp;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'g':
|
||||
regexp = EARGF(usage());
|
||||
if((grep = regcomp9(regexp)) == nil)
|
||||
sysfatal("bad regexp %s", regexp);
|
||||
break;
|
||||
case 'l':
|
||||
longnames++;
|
||||
break;
|
||||
case 'v':
|
||||
chatty++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
getwd(cwd, sizeof cwd);
|
||||
ncwd = strlen(cwd);
|
||||
|
||||
if(argc < 1)
|
||||
usage();
|
||||
fd = open(argv[0], OREAD);
|
||||
if(fd < 0)
|
||||
sysfatal("open %s: %r", argv[0]);
|
||||
if(crackhdr(fd, &fhdr) <= 0)
|
||||
sysfatal("crackhdr: %r");
|
||||
machbytype(fhdr.type);
|
||||
if(syminit(fd, &fhdr) <= 0)
|
||||
sysfatal("syminit: %r");
|
||||
text = loadmap(nil, fd, &fhdr);
|
||||
if(text == nil)
|
||||
sysfatal("loadmap: %r");
|
||||
pid = startprocess(argv);
|
||||
mem = attachproc(pid, &fhdr);
|
||||
if(mem == nil)
|
||||
sysfatal("attachproc: %r");
|
||||
breakpoints.cmp = rangecmp;
|
||||
cover();
|
||||
n = go();
|
||||
walktree(breakpoints.root);
|
||||
if(chatty)
|
||||
print("%d breakpoints\n", n);
|
||||
detachproc(mem);
|
||||
exits(0);
|
||||
}
|
||||
|
246
src/cmd/cov/tree.c
Normal file
246
src/cmd/cov/tree.c
Normal file
@ -0,0 +1,246 @@
|
||||
// Renamed from Map to Tree to avoid conflict with libmach.
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
|
||||
Massachusetts Institute of Technology
|
||||
Portions Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Mutable map structure, but still based on
|
||||
// Okasaki, Red Black Trees in a Functional Setting, JFP 1999,
|
||||
// which is a lot easier than the traditional red-black
|
||||
// and plenty fast enough for me. (Also I could copy
|
||||
// and edit fmap.c.)
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "tree.h"
|
||||
|
||||
#define TreeNode TreeNode
|
||||
#define Tree Tree
|
||||
|
||||
enum
|
||||
{
|
||||
Red = 0,
|
||||
Black = 1
|
||||
};
|
||||
|
||||
|
||||
// Red-black trees are binary trees with this property:
|
||||
// 1. No red node has a red parent.
|
||||
// 2. Every path from the root to a leaf contains the
|
||||
// same number of black nodes.
|
||||
|
||||
static TreeNode*
|
||||
rwTreeNode(TreeNode *p, int color, TreeNode *left, void *key, void *value, TreeNode *right)
|
||||
{
|
||||
if(p == nil)
|
||||
p = malloc(sizeof *p);
|
||||
p->color = color;
|
||||
p->left = left;
|
||||
p->key = key;
|
||||
p->value = value;
|
||||
p->right = right;
|
||||
return p;
|
||||
}
|
||||
|
||||
static TreeNode*
|
||||
balance(TreeNode *m0)
|
||||
{
|
||||
void *xk, *xv, *yk, *yv, *zk, *zv;
|
||||
TreeNode *a, *b, *c, *d;
|
||||
TreeNode *m1, *m2;
|
||||
int color;
|
||||
TreeNode *left, *right;
|
||||
void *key, *value;
|
||||
|
||||
color = m0->color;
|
||||
left = m0->left;
|
||||
key = m0->key;
|
||||
value = m0->value;
|
||||
right = m0->right;
|
||||
|
||||
// Okasaki notation: (T is mkTreeNode, B is Black, R is Red, x, y, z are key-value.
|
||||
//
|
||||
// balance B (T R (T R a x b) y c) z d
|
||||
// balance B (T R a x (T R b y c)) z d
|
||||
// balance B a x (T R (T R b y c) z d)
|
||||
// balance B a x (T R b y (T R c z d))
|
||||
//
|
||||
// = T R (T B a x b) y (T B c z d)
|
||||
|
||||
if(color == Black){
|
||||
if(left && left->color == Red){
|
||||
if(left->left && left->left->color == Red){
|
||||
a = left->left->left;
|
||||
xk = left->left->key;
|
||||
xv = left->left->value;
|
||||
b = left->left->right;
|
||||
yk = left->key;
|
||||
yv = left->value;
|
||||
c = left->right;
|
||||
zk = key;
|
||||
zv = value;
|
||||
d = right;
|
||||
m1 = left;
|
||||
m2 = left->left;
|
||||
goto hard;
|
||||
}else if(left->right && left->right->color == Red){
|
||||
a = left->left;
|
||||
xk = left->key;
|
||||
xv = left->value;
|
||||
b = left->right->left;
|
||||
yk = left->right->key;
|
||||
yv = left->right->value;
|
||||
c = left->right->right;
|
||||
zk = key;
|
||||
zv = value;
|
||||
d = right;
|
||||
m1 = left;
|
||||
m2 = left->right;
|
||||
goto hard;
|
||||
}
|
||||
}else if(right && right->color == Red){
|
||||
if(right->left && right->left->color == Red){
|
||||
a = left;
|
||||
xk = key;
|
||||
xv = value;
|
||||
b = right->left->left;
|
||||
yk = right->left->key;
|
||||
yv = right->left->value;
|
||||
c = right->left->right;
|
||||
zk = right->key;
|
||||
zv = right->value;
|
||||
d = right->right;
|
||||
m1 = right;
|
||||
m2 = right->left;
|
||||
goto hard;
|
||||
}else if(right->right && right->right->color == Red){
|
||||
a = left;
|
||||
xk = key;
|
||||
xv = value;
|
||||
b = right->left;
|
||||
yk = right->key;
|
||||
yv = right->value;
|
||||
c = right->right->left;
|
||||
zk = right->right->key;
|
||||
zv = right->right->value;
|
||||
d = right->right->right;
|
||||
m1 = right;
|
||||
m2 = right->right;
|
||||
goto hard;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rwTreeNode(m0, color, left, key, value, right);
|
||||
|
||||
hard:
|
||||
return rwTreeNode(m0, Red, rwTreeNode(m1, Black, a, xk, xv, b),
|
||||
yk, yv, rwTreeNode(m2, Black, c, zk, zv, d));
|
||||
}
|
||||
|
||||
static TreeNode*
|
||||
ins0(TreeNode *p, void *k, void *v, TreeNode *rw)
|
||||
{
|
||||
if(p == nil)
|
||||
return rwTreeNode(rw, Red, nil, k, v, nil);
|
||||
if(p->key == k){
|
||||
if(rw)
|
||||
return rwTreeNode(rw, p->color, p->left, k, v, p->right);
|
||||
p->value = v;
|
||||
return p;
|
||||
}
|
||||
if(p->key < k)
|
||||
p->left = ins0(p->left, k, v, rw);
|
||||
else
|
||||
p->right = ins0(p->right, k, v, rw);
|
||||
return balance(p);
|
||||
}
|
||||
|
||||
static TreeNode*
|
||||
ins1(Tree *m, TreeNode *p, void *k, void *v, TreeNode *rw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(p == nil)
|
||||
return rwTreeNode(rw, Red, nil, k, v, nil);
|
||||
i = m->cmp(p->key, k);
|
||||
if(i == 0){
|
||||
if(rw)
|
||||
return rwTreeNode(rw, p->color, p->left, k, v, p->right);
|
||||
p->value = v;
|
||||
return p;
|
||||
}
|
||||
if(i < 0)
|
||||
p->left = ins1(m, p->left, k, v, rw);
|
||||
else
|
||||
p->right = ins1(m, p->right, k, v, rw);
|
||||
return balance(p);
|
||||
}
|
||||
|
||||
void
|
||||
treeputelem(Tree *m, void *key, void *val, TreeNode *rw)
|
||||
{
|
||||
if(m->cmp)
|
||||
m->root = ins1(m, m->root, key, val, rw);
|
||||
else
|
||||
m->root = ins0(m->root, key, val, rw);
|
||||
}
|
||||
|
||||
void
|
||||
treeput(Tree *m, void *key, void *val)
|
||||
{
|
||||
treeputelem(m, key, val, nil);
|
||||
}
|
||||
|
||||
void*
|
||||
treeget(Tree *m, void *key)
|
||||
{
|
||||
int i;
|
||||
TreeNode *p;
|
||||
|
||||
p = m->root;
|
||||
if(m->cmp){
|
||||
for(;;){
|
||||
if(p == nil)
|
||||
return nil;
|
||||
i = m->cmp(p->key, key);
|
||||
if(i < 0)
|
||||
p = p->left;
|
||||
else if(i > 0)
|
||||
p = p->right;
|
||||
else
|
||||
return p->value;
|
||||
}
|
||||
}else{
|
||||
for(;;){
|
||||
if(p == nil)
|
||||
return nil;
|
||||
if(p->key == key)
|
||||
return p->value;
|
||||
if(p->key < key)
|
||||
p = p->left;
|
||||
else
|
||||
p = p->right;
|
||||
}
|
||||
}
|
||||
}
|
47
src/cmd/cov/tree.h
Normal file
47
src/cmd/cov/tree.h
Normal file
@ -0,0 +1,47 @@
|
||||
// Renamed from Map to Tree to avoid conflict with libmach.
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
|
||||
Massachusetts Institute of Technology
|
||||
Portions Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
typedef struct Tree Tree;
|
||||
typedef struct TreeNode TreeNode;
|
||||
struct Tree
|
||||
{
|
||||
int (*cmp)(void*, void*);
|
||||
TreeNode *root;
|
||||
};
|
||||
|
||||
struct TreeNode
|
||||
{
|
||||
int color;
|
||||
TreeNode *left;
|
||||
void *key;
|
||||
void *value;
|
||||
TreeNode *right;
|
||||
};
|
||||
|
||||
void *treeget(Tree*, void*);
|
||||
void treeput(Tree*, void*, void*);
|
||||
void treeputelem(Tree*, void*, void*, TreeNode*);
|
@ -4,7 +4,7 @@
|
||||
|
||||
include ../../Make.conf
|
||||
|
||||
# The directory is db because the source is portable and general.
|
||||
# The directory is prof because the source is portable and general.
|
||||
# We call the binary 6prof to avoid confusion and because this binary
|
||||
# is linked only with amd64 and x86 support.
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <mach_amd64.h>
|
||||
#include <ureg_amd64.h>
|
||||
typedef struct Ureg Ureg;
|
||||
#undef waitpid /* want Unix waitpid, not Plan 9 */
|
||||
|
||||
extern mach_port_t mach_reply_port(void); // should be in system headers, is not
|
||||
|
||||
@ -185,6 +186,7 @@ static int nthr;
|
||||
static pthread_mutex_t mu;
|
||||
static pthread_cond_t cond;
|
||||
static void* excthread(void*);
|
||||
static void* waitthread(void*);
|
||||
static mach_port_t excport;
|
||||
|
||||
enum {
|
||||
@ -215,9 +217,10 @@ addpid(int pid, int force)
|
||||
pthread_t p;
|
||||
|
||||
excport = mach_reply_port();
|
||||
pthread_create(&p, nil, excthread, nil);
|
||||
pthread_mutex_init(&mu, nil);
|
||||
pthread_cond_init(&cond, nil);
|
||||
pthread_create(&p, nil, excthread, nil);
|
||||
pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
|
||||
first = 0;
|
||||
}
|
||||
|
||||
@ -483,6 +486,7 @@ machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
|
||||
uint nn;
|
||||
mach_port_t thread;
|
||||
int reg;
|
||||
char buf[100];
|
||||
union {
|
||||
x86_thread_state64_t regs;
|
||||
uchar p[1];
|
||||
@ -517,7 +521,11 @@ machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
|
||||
if(me(thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&u.regs, &nn)) < 0){
|
||||
if(!isr)
|
||||
thread_resume(thread);
|
||||
werrstr("thread_get_state: %r");
|
||||
rerrstr(buf, sizeof buf);
|
||||
if(strcmp(buf, "send invalid dest") == 0)
|
||||
werrstr("process exited");
|
||||
else
|
||||
werrstr("thread_get_state: %r");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -636,14 +644,15 @@ havet:
|
||||
ncode = nelem(t->code);
|
||||
memmove(t->code, code, ncode*sizeof t->code[0]);
|
||||
|
||||
// Suspend thread, so that we can look at it & restart it later.
|
||||
if(me(thread_suspend(thread)) < 0)
|
||||
fprint(2, "catch_exception_raise thread_suspend: %r\n");
|
||||
|
||||
// Synchronize with waitstop below.
|
||||
pthread_mutex_lock(&mu);
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&mu);
|
||||
|
||||
// Suspend thread, so that we can look at it & restart it later.
|
||||
if(me(thread_suspend(thread)) < 0)
|
||||
fprint(2, "catch_exception_raise thread_suspend: %r\n");
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
@ -656,12 +665,29 @@ excthread(void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wait for pid to exit.
|
||||
static int exited;
|
||||
static void*
|
||||
waitthread(void *v)
|
||||
{
|
||||
int pid, status;
|
||||
|
||||
pid = (int)(uintptr)v;
|
||||
waitpid(pid, &status, 0);
|
||||
exited = 1;
|
||||
// Synchronize with waitstop below.
|
||||
pthread_mutex_lock(&mu);
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&mu);
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Wait for thread t to stop.
|
||||
static int
|
||||
waitstop(Thread *t)
|
||||
{
|
||||
pthread_mutex_lock(&mu);
|
||||
while(!threadstopped(t))
|
||||
while(!exited && !threadstopped(t))
|
||||
pthread_cond_wait(&cond, &mu);
|
||||
pthread_mutex_unlock(&mu);
|
||||
return 0;
|
||||
|
@ -672,7 +672,7 @@ textsym(Symbol *s, int index)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Get ith file name
|
||||
*/
|
||||
int
|
||||
@ -894,7 +894,7 @@ file2pc(char *file, int32 line)
|
||||
if(name == 0) { /* encode the file name */
|
||||
werrstr("file %s not found", file);
|
||||
return ~0;
|
||||
}
|
||||
}
|
||||
/* find this history stack */
|
||||
for(i = 0, fp = files; i < nfiles; i++, fp++)
|
||||
if (hline(fp, name, &line))
|
||||
@ -1019,7 +1019,7 @@ hline(File *fp, short *name, int32 *line)
|
||||
else if(depth++ == 1) /* push */
|
||||
offset -= hp->line;
|
||||
} else if(--depth == 1) /* pop */
|
||||
offset += hp->line;
|
||||
offset += hp->line;
|
||||
}
|
||||
*line = ln+offset;
|
||||
return 1;
|
||||
@ -1163,6 +1163,8 @@ fileelem(Sym **fp, uchar *cp, char *buf, int n)
|
||||
bp = buf;
|
||||
end = buf+n-1;
|
||||
for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
|
||||
if(j >= fmaxi) // TODO(rsc): should not happen, but does!
|
||||
break;
|
||||
c = fp[j]->name;
|
||||
if(bp != buf && bp[-1] != '/' && bp < end)
|
||||
*bp++ = '/';
|
||||
@ -1277,7 +1279,7 @@ pc2sp(uvlong pc)
|
||||
currsp += 4*u;
|
||||
else if (u < 129)
|
||||
currsp -= 4*(u-64);
|
||||
else
|
||||
else
|
||||
currpc += mach->pcquant*(u-129);
|
||||
currpc += mach->pcquant;
|
||||
}
|
||||
@ -1316,7 +1318,7 @@ pc2line(uvlong pc)
|
||||
currline += u;
|
||||
else if(u < 129)
|
||||
currline -= (u-64);
|
||||
else
|
||||
else
|
||||
currpc += mach->pcquant*(u-129);
|
||||
currpc += mach->pcquant;
|
||||
}
|
||||
@ -1371,7 +1373,7 @@ line2addr(int32 line, uvlong basepc, uvlong endpc)
|
||||
currline += u;
|
||||
else if(u < 129)
|
||||
currline -= (u-64);
|
||||
else
|
||||
else
|
||||
currpc += mach->pcquant*(u-129);
|
||||
currpc += mach->pcquant;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user