loadProgramSize calculate a program/data size breakdown of each package for a given ELF file. If the file doesn't contain DWARF debug information, the returned program size will still have valid summaries but won't have complete size information per package.
(path string, packagePathMap map[string]string)
| 419 | // size will still have valid summaries but won't have complete size information |
| 420 | // per package. |
| 421 | func loadProgramSize(path string, packagePathMap map[string]string) (*programSize, error) { |
| 422 | // Open the binary file. |
| 423 | f, err := os.Open(path) |
| 424 | if err != nil { |
| 425 | return nil, err |
| 426 | } |
| 427 | defer f.Close() |
| 428 | |
| 429 | // This stores all chunks of addresses found in the binary. |
| 430 | var addresses []addressLine |
| 431 | |
| 432 | // Load the binary file, which could be in a number of file formats. |
| 433 | var sections []memorySection |
| 434 | if file, err := elf.NewFile(f); err == nil { |
| 435 | var codeAlignment uint64 |
| 436 | switch file.Machine { |
| 437 | case elf.EM_ARM: |
| 438 | codeAlignment = 4 // usually 2, but can be 4 |
| 439 | } |
| 440 | // Read DWARF information. The error is intentionally ignored. |
| 441 | data, _ := file.DWARF() |
| 442 | if data != nil { |
| 443 | addresses, err = readProgramSizeFromDWARF(data, 0, codeAlignment, true) |
| 444 | if err != nil { |
| 445 | // However, _do_ report an error here. Something must have gone |
| 446 | // wrong while trying to parse DWARF data. |
| 447 | return nil, err |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | // Read the ELF symbols for some more chunks of location information. |
| 452 | // Some globals (such as strings) aren't stored in the DWARF debug |
| 453 | // information and therefore need to be obtained in a different way. |
| 454 | allSymbols, err := file.Symbols() |
| 455 | if err != nil { |
| 456 | return nil, err |
| 457 | } |
| 458 | for _, symbol := range allSymbols { |
| 459 | symType := elf.ST_TYPE(symbol.Info) |
| 460 | if symbol.Size == 0 { |
| 461 | continue |
| 462 | } |
| 463 | if symType != elf.STT_FUNC && symType != elf.STT_OBJECT && symType != elf.STT_NOTYPE { |
| 464 | continue |
| 465 | } |
| 466 | if symbol.Section >= elf.SHN_LORESERVE { |
| 467 | // Not a regular section, so skip it. |
| 468 | // One example is elf.SHN_ABS, which is used for symbols |
| 469 | // declared with an absolute value such as the memset function |
| 470 | // on the ESP32 which is defined in the mask ROM. |
| 471 | continue |
| 472 | } |
| 473 | section := file.Sections[symbol.Section] |
| 474 | if section.Flags&elf.SHF_ALLOC == 0 { |
| 475 | continue |
| 476 | } |
| 477 | if packageSymbolRegexp.MatchString(symbol.Name) || symbol.Name == "__isr_vector" { |
| 478 | addresses = append(addresses, addressLine{ |