| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /* this file parses a library file for the build and returns |
| * a list of all the symbols with their types and sizes */ |
| |
| /* gets an objdump -t and parses into a symbolMap" */ |
| |
| package builder |
| |
| import ( |
| "bytes" |
| "path/filepath" |
| "regexp" |
| "strconv" |
| |
| "mynewt.apache.org/newt/newt/symbol" |
| "mynewt.apache.org/newt/util" |
| ) |
| |
| /* This is a tricky thing to parse. Right now, I keep all the |
| * flags together and just store the offset, size, name and flags. |
| * 00012970 l .bss 00000000 _end |
| * 00011c60 l .init_array 00000000 __init_array_start |
| * 00011c60 l .init_array 00000000 __preinit_array_start |
| * 000084b0 g F .text 00000034 os_arch_start |
| * 00000000 g .debug_aranges 00000000 __HeapBase |
| * 00011c88 g O .data 00000008 g_os_task_list |
| * 000082cc g F .text 0000004c os_idle_task |
| * 000094e0 g F .text 0000002e .hidden __gnu_uldivmod_helper |
| * 00000000 g .svc_table 00000000 SVC_Count |
| * 000125e4 g O .bss 00000004 g_console_is_init |
| * 00009514 g F .text 0000029c .hidden __divdi3 |
| * 000085a8 g F .text 00000054 os_eventq_put |
| * 00000100 O *COM* 00000004 g_idle_task_stack |
| |
| */ |
| func parseObjectLine(line string, r *regexp.Regexp) (error, *symbol.SymbolInfo) { |
| |
| answer := r.FindAllStringSubmatch(line, 11) |
| |
| if len(answer) == 0 { |
| return nil, nil |
| } |
| |
| data := answer[0] |
| |
| if len(data) != 6 { |
| util.StatusMessage(util.VERBOSITY_DEFAULT, |
| "Not enough content in object file line --- %s", line) |
| return nil, nil |
| } |
| |
| si := symbol.NewSymbolInfo() |
| |
| si.Name = data[5] |
| |
| v, err := strconv.ParseUint(data[1], 16, 32) |
| |
| if err != nil { |
| util.StatusMessage(util.VERBOSITY_DEFAULT, |
| "Could not convert location from object file line --- %s", line) |
| return nil, nil |
| } |
| |
| si.Loc = int(v) |
| |
| v, err = strconv.ParseUint(data[4], 16, 32) |
| |
| if err != nil { |
| util.StatusMessage(util.VERBOSITY_DEFAULT, |
| "Could not convert size form object file line --- %s", line) |
| return nil, nil |
| } |
| |
| si.Size = int(v) |
| si.Code = data[2] |
| si.Section = data[3] |
| |
| /* Common section has length in a different spot. Also, these |
| * are really global variables so mark them as such */ |
| if si.IsSection("*COM*") { |
| si.Size = (*si).Loc |
| si.Code = "g" + si.Code[1:] |
| } |
| |
| return nil, si |
| } |
| |
| func getParseRexeg() (error, *regexp.Regexp) { |
| r, err := regexp.Compile("^([0-9A-Fa-f]+)[\t ]+([lgu! ][w ][C ][W ][Ii ][Dd ][FfO ])[\t ]+([^\t\n\f\r ]+)[\t ]+([0-9a-fA-F]+)[\t ]([^\t\n\f\r ]+)") |
| |
| if err != nil { |
| return err, nil |
| } |
| |
| return nil, r |
| } |
| |
| func (b *Builder) ParseObjectLibrary(bp *BuildPackage) ( |
| error, *symbol.SymbolMap) { |
| |
| file := b.ArchivePath(bp) |
| return b.ParseObjectLibraryFile(bp, file, true) |
| } |
| |
| func (b *Builder) ParseObjectElf(elf_file string) (error, *symbol.SymbolMap) { |
| return b.ParseObjectLibraryFile(nil, elf_file, false) |
| } |
| |
| func (b *Builder) ParseObjectLibraryFile(bp *BuildPackage, |
| file string, textDataOnly bool) (error, *symbol.SymbolMap) { |
| |
| c, err := b.targetBuilder.NewCompiler(b.AppElfPath(), "") |
| |
| ext := filepath.Ext(file) |
| |
| if err != nil { |
| return err, nil |
| } |
| |
| err, out := c.ParseLibrary(file) |
| |
| if err != nil { |
| return err, nil |
| } |
| |
| sm := symbol.NewSymbolMap() |
| |
| buffer := bytes.NewBuffer(out) |
| |
| err, r := getParseRexeg() |
| |
| if err != nil { |
| return err, nil |
| } |
| |
| for { |
| line, err := buffer.ReadString('\n') |
| if err != nil { |
| break |
| } |
| err, si := parseObjectLine(line, r) |
| |
| if err == nil && si != nil { |
| |
| /* assign the library */ |
| if bp != nil { |
| (*si).Bpkg = bp.rpkg.Lpkg.Name() |
| } else { |
| (*si).Bpkg = "elf" |
| } |
| |
| /* discard undefined */ |
| if (*si).IsSection("*UND*") { |
| continue |
| } |
| |
| /* discard debug symbols */ |
| if (*si).IsDebug() { |
| continue |
| } |
| |
| if (*si).IsFile() { |
| continue |
| } |
| |
| /* if we are looking for text and data only, do a special check */ |
| if textDataOnly { |
| include := (*si).IsSection(".bss") || |
| (*si).IsSection(".text") || |
| (*si).IsSection(".data") || |
| (*si).IsSection("*COM*") || |
| (*si).IsSection(".rodata") |
| |
| if !include { |
| continue |
| } |
| } |
| |
| /* add the symbol to the map */ |
| (*si).Ext = ext |
| sm.Add(*si) |
| util.StatusMessage(util.VERBOSITY_VERBOSE, |
| "Keeping Symbol %s in package %s\n", (*si).Name, (*si).Bpkg) |
| } |
| } |
| |
| return nil, sm |
| } |
| |
| func (b *Builder) CopySymbols(sm *symbol.SymbolMap) error { |
| c, err := b.targetBuilder.NewCompiler(b.AppElfPath(), "") |
| |
| if err != nil { |
| return err |
| } |
| |
| err = c.CopySymbols(b.AppElfPath(), b.AppLinkerElfPath(), sm) |
| |
| return err |
| } |