github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/cmd/ld/pcln.c (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "l.h" 6 #include "lib.h" 7 #include "../../runtime/funcdata.h" 8 9 static void 10 addvarint(Pcdata *d, uint32 val) 11 { 12 int32 n; 13 uint32 v; 14 uchar *p; 15 16 n = 0; 17 for(v = val; v >= 0x80; v >>= 7) 18 n++; 19 n++; 20 21 if(d->n + n > d->m) { 22 d->m = (d->n + n)*2; 23 d->p = erealloc(d->p, d->m); 24 } 25 26 p = d->p + d->n; 27 for(v = val; v >= 0x80; v >>= 7) 28 *p++ = v | 0x80; 29 *p = v; 30 d->n += n; 31 } 32 33 static int32 34 addpctab(LSym *ftab, int32 off, Pcdata *d) 35 { 36 int32 start; 37 38 start = ftab->np; 39 symgrow(ctxt, ftab, start + d->n); 40 memmove(ftab->p + start, d->p, d->n); 41 42 return setuint32(ctxt, ftab, off, start); 43 } 44 45 static int32 46 ftabaddstring(LSym *ftab, char *s) 47 { 48 int32 n, start; 49 50 n = strlen(s)+1; 51 start = ftab->np; 52 symgrow(ctxt, ftab, start+n+1); 53 strcpy((char*)ftab->p + start, s); 54 return start; 55 } 56 57 static void 58 renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d) 59 { 60 int i; 61 LSym *f; 62 Pcdata out; 63 Pciter it; 64 uint32 v; 65 int32 oldval, newval, val, dv; 66 67 // Give files numbers. 68 for(i=0; i<nfiles; i++) { 69 f = files[i]; 70 if(f->type != SFILEPATH) { 71 f->value = ++ctxt->nhistfile; 72 f->type = SFILEPATH; 73 f->next = ctxt->filesyms; 74 ctxt->filesyms = f; 75 } 76 } 77 78 newval = -1; 79 memset(&out, 0, sizeof out); 80 81 for(pciterinit(ctxt, &it, d); !it.done; pciternext(&it)) { 82 // value delta 83 oldval = it.value; 84 if(oldval == -1) 85 val = -1; 86 else { 87 if(oldval < 0 || oldval >= nfiles) 88 sysfatal("bad pcdata %d", oldval); 89 val = files[oldval]->value; 90 } 91 dv = val - newval; 92 newval = val; 93 v = ((uint32)dv<<1) ^ (uint32)(int32)(dv>>31); 94 addvarint(&out, v); 95 96 // pc delta 97 addvarint(&out, (it.nextpc - it.pc) / it.pcscale); 98 } 99 100 // terminating value delta 101 addvarint(&out, 0); 102 103 free(d->p); 104 *d = out; 105 } 106 107 108 // pclntab initializes the pclntab symbol with 109 // runtime function and file name information. 110 void 111 pclntab(void) 112 { 113 int32 i, nfunc, start, funcstart; 114 LSym *ftab, *s; 115 int32 off, end, frameptrsize; 116 int64 funcdata_bytes; 117 Pcln *pcln; 118 Pciter it; 119 static Pcln zpcln; 120 121 funcdata_bytes = 0; 122 ftab = linklookup(ctxt, "runtime.pclntab", 0); 123 ftab->type = SPCLNTAB; 124 ftab->reachable = 1; 125 126 // See golang.org/s/go12symtab for the format. Briefly: 127 // 8-byte header 128 // nfunc [PtrSize bytes] 129 // function table, alternating PC and offset to func struct [each entry PtrSize bytes] 130 // end PC [PtrSize bytes] 131 // offset to file table [4 bytes] 132 nfunc = 0; 133 for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) 134 nfunc++; 135 symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4); 136 setuint32(ctxt, ftab, 0, 0xfffffffb); 137 setuint8(ctxt, ftab, 6, MINLC); 138 setuint8(ctxt, ftab, 7, PtrSize); 139 setuintxx(ctxt, ftab, 8, nfunc, PtrSize); 140 141 nfunc = 0; 142 for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) { 143 pcln = ctxt->cursym->pcln; 144 if(pcln == nil) 145 pcln = &zpcln; 146 147 funcstart = ftab->np; 148 funcstart += -ftab->np & (PtrSize-1); 149 150 setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym); 151 setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize); 152 153 // fixed size of struct, checked below 154 off = funcstart; 155 end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize; 156 if(pcln->nfuncdata > 0 && (end&(PtrSize-1))) 157 end += 4; 158 symgrow(ctxt, ftab, end); 159 160 // entry uintptr 161 off = setaddr(ctxt, ftab, off, ctxt->cursym); 162 163 // name int32 164 off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name)); 165 166 // args int32 167 // TODO: Move into funcinfo. 168 off = setuint32(ctxt, ftab, off, ctxt->cursym->args); 169 170 // frame int32 171 // TODO: Remove entirely. The pcsp table is more precise. 172 // This is only used by a fallback case during stack walking 173 // when a called function doesn't have argument information. 174 // We need to make sure everything has argument information 175 // and then remove this. 176 frameptrsize = PtrSize; 177 if(ctxt->cursym->leaf) 178 frameptrsize = 0; 179 off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize); 180 181 if(pcln != &zpcln) { 182 renumberfiles(ctxt, pcln->file, pcln->nfile, &pcln->pcfile); 183 if(0) { 184 // Sanity check the new numbering 185 for(pciterinit(ctxt, &it, &pcln->pcfile); !it.done; pciternext(&it)) { 186 if(it.value < 1 || it.value > ctxt->nhistfile) { 187 diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, ctxt->nhistfile); 188 errorexit(); 189 } 190 } 191 } 192 } 193 194 // pcdata 195 off = addpctab(ftab, off, &pcln->pcsp); 196 off = addpctab(ftab, off, &pcln->pcfile); 197 off = addpctab(ftab, off, &pcln->pcline); 198 off = setuint32(ctxt, ftab, off, pcln->npcdata); 199 off = setuint32(ctxt, ftab, off, pcln->nfuncdata); 200 for(i=0; i<pcln->npcdata; i++) 201 off = addpctab(ftab, off, &pcln->pcdata[i]); 202 203 // funcdata, must be pointer-aligned and we're only int32-aligned. 204 // Missing funcdata will be 0 (nil pointer). 205 if(pcln->nfuncdata > 0) { 206 if(off&(PtrSize-1)) 207 off += 4; 208 for(i=0; i<pcln->nfuncdata; i++) { 209 if(pcln->funcdata[i] == nil) 210 setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize); 211 else { 212 // TODO: Dedup. 213 funcdata_bytes += pcln->funcdata[i]->size; 214 setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]); 215 } 216 } 217 off += pcln->nfuncdata*PtrSize; 218 } 219 220 if(off != end) { 221 diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, PtrSize); 222 errorexit(); 223 } 224 225 // Final entry of table is just end pc. 226 if(ctxt->cursym->next == nil) 227 setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size); 228 } 229 230 // Start file table. 231 start = ftab->np; 232 start += -ftab->np & (PtrSize-1); 233 setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start); 234 235 symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4); 236 setuint32(ctxt, ftab, start, ctxt->nhistfile); 237 for(s = ctxt->filesyms; s != S; s = s->next) 238 setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name)); 239 240 ftab->size = ftab->np; 241 242 if(debug['v']) 243 Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes); 244 }