blob: 9d155cafa8cc1ee50a8da32f96118e53cb66a0ea [file] [log] [blame]
/**
* 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
}