@@ -3,6 +3,8 @@ package common
33import (
44 "bufio"
55 "bytes"
6+ "debug/elf"
7+ "errors"
68 "fmt"
79 "os"
810 "sort"
@@ -196,7 +198,7 @@ type Ksym struct {
196198}
197199
198200type Ksyms struct {
199- Syms []Ksym
201+ syms []Ksym
200202 // Strs string
201203}
202204
@@ -220,31 +222,30 @@ func LoadKsyms() (*Ksyms, error) {
220222 return nil , err
221223 }
222224 name := fields [2 ]
223- ksyms .Syms = append (ksyms .Syms , Ksym {
225+ ksyms .syms = append (ksyms .syms , Ksym {
224226 Name : name ,
225227 Addr : addr ,
226228 })
227229 }
228230
229- syms := ksyms .Syms
231+ syms := ksyms .syms
230232 sort .Slice (syms , func (i , j int ) bool {
231233 if syms [i ].Addr == syms [j ].Addr {
232234 return syms [i ].Name >= syms [j ].Name
233235 }
234236 return syms [i ].Addr >= syms [j ].Addr
235237 })
236238
237- ksyms .Syms = syms
239+ ksyms .syms = syms
238240 return ksyms , nil
239241}
240242
241243func (k * Ksyms ) MapAddr (addr uint64 ) * Ksym {
242- syms := k .Syms
244+ syms := k .syms
243245 i := sort .Search (len (syms ), func (i int ) bool {
244246 return syms [i ].Addr <= addr
245247 })
246248
247- // fmt.Printf("%d ? %d\n", addr, i)
248249 if i < len (syms ) {
249250 v := syms [i ]
250251 return & v
@@ -253,11 +254,307 @@ func (k *Ksyms) MapAddr(addr uint64) *Ksym {
253254}
254255
255256func (k * Ksyms ) GetSymbol (name string ) * Ksym {
256- for _ , v := range k .Syms {
257+ for _ , v := range k .syms {
257258 v := v
258259 if v .Name == name {
259260 return & v
260261 }
261262 }
262263 return nil
263264}
265+
266+ type LoadRange struct {
267+ start uint64
268+ end uint64
269+ fileOff uint64
270+ }
271+
272+ const (
273+ EXEC = iota
274+ DYN
275+ PERF_MAP
276+ VDSO
277+ UNKNOWN
278+ )
279+
280+ type Sym struct {
281+ Name string
282+ start uint
283+ size uint
284+ }
285+
286+ type Syms struct {
287+ dsos []Dso
288+ }
289+
290+ func (s * Syms ) MapAddr (addr uint64 ) * Sym {
291+ d , _ := s .findDso (addr )
292+ if d == nil {
293+ return nil
294+ }
295+ return nil
296+ }
297+
298+ func (s * Syms ) findDso (addr uint64 ) (* Dso , uint64 ) {
299+ var offset uint64
300+ for _ , d := range s .dsos {
301+ for _ , r := range d .ranges {
302+ if addr <= r .start || addr >= r .end {
303+ continue
304+ }
305+ if d ._type == DYN || d ._type == VDSO {
306+ /* Offset within the mmap */
307+ offset = addr - r .start + r .fileOff
308+ /* Offset within the ELF for dyn symbol lookup */
309+ offset += d .shAddr - d .shOffset
310+ } else {
311+ offset = addr
312+ }
313+ return & d , offset
314+ }
315+ }
316+
317+ return nil , 0
318+ }
319+
320+ func (s * Syms ) find_sym () {
321+
322+ }
323+
324+ type Dso struct {
325+ name string
326+ ranges []LoadRange
327+ // range_sz int
328+ /* Dyn's first text section virtual addr at execution */
329+ shAddr uint64
330+ /* Dyn's first text section file offset */
331+ shOffset uint64
332+ _type int
333+ syms []Sym
334+
335+ /*
336+ * libbpf's struct btf is actually a pretty efficient
337+ * "set of strings" data structure, so we create an
338+ * empty one and use it to store symbol names.
339+ */
340+ // struct btf *btf;
341+ }
342+
343+ func (d * Dso ) findSym (offset uint64 ) * Sym {
344+ syms := d .syms
345+ i := sort .Search (len (syms ), func (i int ) bool {
346+ // return syms[i].Addr <= addr
347+ return true
348+ })
349+
350+ if i < len (syms ) {
351+ v := syms [i ]
352+ return & v
353+ }
354+ return nil
355+ }
356+
357+ func (d * Dso ) loadSymTable () error {
358+ switch d ._type {
359+ case PERF_MAP :
360+ return d .loadSymTableFromPerfMap ()
361+ case EXEC , DYN :
362+ return d .loadSymTableFromElf (0 )
363+ case VDSO :
364+ return d .loadSymTableFromVdsoImage ()
365+ default :
366+ return errors .New ("unsupported type" )
367+ }
368+ }
369+
370+ func (d * Dso ) loadSymTableFromPerfMap () error {
371+ return errors .New ("unsupported type" )
372+ }
373+
374+ func (d * Dso ) loadSymTableFromElf (fd int ) error {
375+ return nil
376+ }
377+
378+ func (d * Dso ) loadSymTableFromVdsoImage () error {
379+ return nil
380+ }
381+
382+ type SymsCache struct {
383+ data []SymsCacheData
384+ // Nr int
385+ }
386+
387+ type SymsCacheData struct {
388+ syms Syms
389+ tgid int
390+ }
391+
392+ func NewSymsCache () * SymsCache {
393+ return & SymsCache {}
394+ }
395+
396+ func (s * SymsCache ) GetSyms (tgid int ) (* Syms , error ) {
397+ for _ , d := range s .data {
398+ if d .tgid == tgid {
399+ return & d .syms , nil
400+ }
401+ }
402+
403+ syms , err := symsLoadPid (tgid )
404+ if err != nil {
405+ return nil , err
406+ }
407+ s .data = append (s .data , SymsCacheData {
408+ syms : * syms ,
409+ tgid : tgid ,
410+ })
411+ return syms , nil
412+ }
413+
414+ func (s * Syms ) addDso (m addrMap , name string ) error {
415+ var d * Dso
416+ for _ , item := range s .dsos {
417+ if item .name == name {
418+ d = & item
419+ }
420+ }
421+ if d == nil {
422+ d = & Dso {
423+ name : name ,
424+ }
425+ }
426+ d .ranges = append (d .ranges , LoadRange {
427+ start : m .startAddr ,
428+ end : m .endAddr ,
429+ fileOff : m .fileOff ,
430+ })
431+
432+ elfType , err := getElfType (name )
433+ if err != nil {
434+ return err
435+ }
436+ if elfType == elf .ET_EXEC {
437+ d ._type = EXEC
438+ } else if elfType == elf .ET_DYN {
439+ d ._type = DYN
440+ var err error
441+ d .shAddr , d .shOffset , err = getElfTextScnInfo (name )
442+ if err != nil {
443+ return err
444+ }
445+ } else if isPerfMap (name ) {
446+ d ._type = PERF_MAP
447+ } else if isVdso (name ) {
448+ d ._type = VDSO
449+ } else {
450+ d ._type = UNKNOWN
451+ }
452+
453+ return nil
454+ }
455+
456+ func getElfTextScnInfo (path string ) (uint64 , uint64 , error ) {
457+ f , err := elf .Open (path )
458+ if err != nil {
459+ return 0 , 0 , err
460+ }
461+ defer f .Close ()
462+ for _ , s := range f .Sections {
463+ if s .Name == ".text" {
464+ return s .Addr , s .Offset , nil
465+ }
466+ }
467+ return 0 , 0 , errors .New ("not found" )
468+ }
469+
470+ func getElfType (path string ) (elf.Type , error ) {
471+ if isVdso (path ) {
472+ return 0 , nil
473+ }
474+ f , err := elf .Open (path )
475+ if err != nil {
476+ return 0 , err
477+ }
478+ f .Close ()
479+ return f .Type , nil
480+ }
481+
482+ func symsLoadPid (tgid int ) (* Syms , error ) {
483+ name := fmt .Sprintf ("/proc/%d/maps" , tgid )
484+ return symsLoadFile (name )
485+ }
486+
487+ type addrMap struct {
488+ startAddr uint64
489+ endAddr uint64
490+ fileOff uint64
491+ devMajor uint64
492+ devMinor uint64
493+ inode uint64
494+ }
495+
496+ func symsLoadFile (name string ) (* Syms , error ) {
497+ fdata , err := os .ReadFile (name )
498+ if err != nil {
499+ return nil , err
500+ }
501+ var syms * Syms
502+ s := bufio .NewScanner (bytes .NewReader (fdata ))
503+ for s .Scan () {
504+ line := strings .TrimSpace (s .Text ())
505+ if line == "" {
506+ continue
507+ }
508+ var addrMap addrMap
509+ var perm string
510+ var name string
511+ n , err := fmt .Fscanf (strings .NewReader (line ),
512+ "%x-%x %4s %x %x:%x %u%s" ,
513+ & addrMap .startAddr , & addrMap .endAddr , & perm , & addrMap .fileOff ,
514+ & addrMap .devMajor , & addrMap .devMinor , & addrMap .inode , & name )
515+ if err != nil {
516+ return nil , err
517+ }
518+ if n == 0 {
519+ continue
520+ }
521+ if len (perm ) < 3 || perm [2 ] != 'x' {
522+ continue
523+ }
524+ if ! isFileBacked (name ) {
525+ continue
526+ }
527+ if isVdso (name ) {
528+ break
529+ }
530+ if err := syms .addDso (addrMap , name ); err != nil {
531+ return nil , err
532+ }
533+ }
534+
535+ return syms , nil
536+ }
537+
538+ func isFileBacked (mapname string ) bool {
539+ if mapname == "" {
540+ return false
541+ }
542+ if strings .HasPrefix (mapname , "//anon" ) ||
543+ strings .HasPrefix (mapname , "/dev/zero" ) ||
544+ strings .HasPrefix (mapname , "/anon_hugepage" ) ||
545+ strings .HasPrefix (mapname , "[stack" ) ||
546+ strings .HasPrefix (mapname , "/SYSV" ) ||
547+ strings .HasPrefix (mapname , "[heap]" ) ||
548+ strings .HasPrefix (mapname , "[vsyscall]" ) {
549+ return false
550+ }
551+ return true
552+ }
553+
554+ func isVdso (path string ) bool {
555+ return path == "[vdso]"
556+ }
557+
558+ func isPerfMap (path string ) bool {
559+ return false
560+ }
0 commit comments