newt/symbol/symbol.go (232 lines of code) (raw):

/** * 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 maintains a list of all the symbols from a */ package symbol import ( "fmt" "sort" "strings" "mynewt.apache.org/newt/util" ) type SymbolInfo struct { Bpkg string Name string Code string Section string Ext string Size int Loc int } type SymbolMap map[string]SymbolInfo func NewSymbolMap() *SymbolMap { val := &SymbolMap{} return val } func NewSymbolInfo() *SymbolInfo { val := &SymbolInfo{} return val } func NewElfSymbol(name string) *SymbolInfo { val := NewSymbolInfo() val.Name = name val.Ext = ".elf" return val } func (s *SymbolMap) Add(info SymbolInfo) { (*s)[info.Name] = info } func (s *SymbolMap) GlobalFunctionsOnly() *SymbolMap { s3 := NewSymbolMap() for _, info1 := range *s { if info1.IsFunction() && !info1.IsLocal() { s3.Add(info1) } } return s3 } func (s *SymbolMap) GlobalDataOnly() *SymbolMap { s3 := NewSymbolMap() for _, info1 := range *s { if !info1.IsFunction() && !info1.IsLocal() { s3.Add(info1) } } return s3 } func (s *SymbolMap) Packages() map[string]bool { pkg := make(map[string]bool) for _, info1 := range *s { pkg[info1.Bpkg] = true } return pkg } func IdenticalUnion(s1 *SymbolMap, s2 *SymbolMap, comparePkg bool, compareAddr bool) (error, *SymbolMap, *SymbolMap) { s3 := NewSymbolMap() s_no := NewSymbolMap() var err_str string var err error /* look through all symbols in S1 and if they are in s1, * add to new map s3 */ for name, info1 := range *s1 { if info2, ok := (*s2)[name]; ok { var pkg bool var addr bool if comparePkg { pkg = info1.Bpkg == info2.Bpkg } else { pkg = true } if compareAddr { addr = info1.Loc == info2.Loc } else { addr = true } /* compare to info 1 */ if info1.Code == info2.Code && info1.Size == info2.Size && pkg && addr { s3.Add(info1) } else if !info1.IsLocal() && !info1.IsFunction() { /* Here is an unusual case. We have a global data * symbol (bss or data) with the same name that is used * in both apps. If code is linked against both of these * the code in the loader will call one while the code in * the app will call the other. If the intention was for * these to be the same, then things are bad. */ if err_str == "" { err_str = "There are global symbols with the same name that " + "are access via the loader and split application. These " + "symbols are either different sizes or from different " + "packages. Reconcile this issue before buidling. If the " + "symbols are intended to be shared by both, move the " + "symbol to a package that is shared by both apps. If " + "the symbols are distict (not shared), then make them " + "static or rename them so they do not conflict" + "\nNon Matching Symbols:\n" } err_str = err_str + fmt.Sprintf("%s-%s\n", info1.Sprintf(), info2.Sprintf()) } else { info1.Name = info1.Name + "(app)" info2.Name = info2.Name + "(loader)" s_no.Add(info1) s_no.Add(info2) } } } if err_str != "" { err = util.NewNewtError(err_str) } return err, s3, s_no } type SymbolMapIterator func(s *SymbolInfo) func sprintfSi(si *SymbolInfo) string { str := fmt.Sprintf(" %32s(%4s) (%8s) -- (%12s) %5d (0x%08x) from %s\n", (*si).Name, (*si).Ext, (*si).Code, (*si).Section, (*si).Size, (*si).Loc, (*si).Bpkg) return str } func dumpSi(si *SymbolInfo) { fmt.Printf(sprintfSi(si)) } func (si *SymbolInfo) Dump() { dumpSi(si) } func (si *SymbolInfo) Sprintf() string { return sprintfSi(si) } func (si *SymbolInfo) IsLocal() bool { val := (*si).Code[:1] if val == "l" { return true } return false } func (si *SymbolInfo) IsWeak() bool { val := (*si).Code[1:2] if val == "w" { return true } return false } func (si *SymbolInfo) IsDebug() bool { val := (*si).Code[5:6] if val == "d" { return true } return false } func (si *SymbolInfo) IsSection(section string) bool { val := (*si).Section return strings.HasPrefix(val, section) } func (si *SymbolInfo) IsFile() bool { val := (*si).Code[6:7] if val == "f" { return true } return false } func (si *SymbolInfo) IsFunction() bool { val := (*si).Code[6:7] if val == "F" { return true } return false } func (s *SymbolMap) FilterPkg(pname string) *SymbolMap { sm := NewSymbolMap() for _, info1 := range *s { if pname != "" && pname == info1.Bpkg { sm.Add(info1) } } return sm } func (s *SymbolMap) String(name string) string { // To store the keys in slice in sorted order var keys []string for k := range *s { keys = append(keys, k) } sort.Strings(keys) // To perform the opertion you want out := fmt.Sprintf("Dumping symbols in file: %s\n", name) for _, k := range keys { info1 := (*s)[k] out += info1.Sprintf() } return out } func (s *SymbolMap) Dump(name string) { // To store the keys in slice in sorted order var keys []string for k := range *s { keys = append(keys, k) } sort.Strings(keys) // To perform the opertion you want fmt.Printf("Dumping symbols in file: %s\n", name) for _, k := range keys { info1 := (*s)[k] info1.Dump() } } // Merge - merges given maps into 1 map // values will be overridden by last matching key - value func (s1 *SymbolMap) Merge(s2 *SymbolMap) (*SymbolMap, error) { for k, v := range *s2 { if val, ok := (*s1)[k]; ok { /* We already have this in the MAP */ if val.IsWeak() && !v.IsWeak() { (*s1)[k] = v } else if v.IsWeak() && !val.IsWeak() { /* nothing to do here as this is OK not to replace */ } else if v.IsLocal() && val.IsLocal() { /* two locals that must conflict with name */ /* have to have separate instances of these */ util.StatusMessage(util.VERBOSITY_VERBOSE, "Local Symbol Conflict: %s from packages %s and %s \n", v.Name, v.Bpkg, val.Bpkg) (*s2).Remove(k) } else { util.StatusMessage(util.VERBOSITY_QUIET, "Global Symbol Conflict: %s from packages %s and %s \n", v.Name, v.Bpkg, val.Bpkg) return nil, util.NewNewtError("Global Symbol Conflict") } } else { (*s1)[k] = v } } return s1, nil } func (s *SymbolMap) Remove(name string) { delete(*s, name) } func (s *SymbolMap) RemoveMap(subset *SymbolMap) { for name, _ := range *subset { (*s).Remove(name) } } /* Returns true if the symbol is present in the symbol map */ func (s *SymbolMap) Find(name string) (*SymbolInfo, bool) { val, ok := (*s)[name] return &val, ok }