summaryrefslogtreecommitdiffstats
path: root/src/build
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2013-07-11 12:05:50 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2013-07-30 14:54:28 -0500
commit86006f63a0d659af62523b94363e8be41fd91bbf (patch)
treed7462a43a9170bcce9b7874aeb56be5085197c1c /src/build
parentd83daa515aba95f7c756fe3406d79076cc6f57cd (diff)
downloadtalos-hostboot-86006f63a0d659af62523b94363e8be41fd91bbf.tar.gz
talos-hostboot-86006f63a0d659af62523b94363e8be41fd91bbf.zip
Convert gensyms to C++
Change-Id: I435996d29ca6c7ad4ce892302729089a2767e643 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/5549 Reviewed-by: Brian H. Horton <brianh@linux.ibm.com> Tested-by: Jenkins Server Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/build')
-rw-r--r--src/build/linker/.gitignore1
-rw-r--r--src/build/linker/gensyms.C364
-rw-r--r--src/build/linker/makefile8
-rw-r--r--src/build/mkrules/images.rules.mk2
-rwxr-xr-xsrc/build/tools/gensyms158
5 files changed, 372 insertions, 161 deletions
diff --git a/src/build/linker/.gitignore b/src/build/linker/.gitignore
index 6b243f5f3..992cfdb19 100644
--- a/src/build/linker/.gitignore
+++ b/src/build/linker/.gitignore
@@ -1 +1,2 @@
linker
+gensyms
diff --git a/src/build/linker/gensyms.C b/src/build/linker/gensyms.C
new file mode 100644
index 000000000..48f018d17
--- /dev/null
+++ b/src/build/linker/gensyms.C
@@ -0,0 +1,364 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/build/linker/gensyms.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2013 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#include <cstdio>
+#include <cstdlib>
+#include <vector>
+#include <map>
+#include <string>
+#include <stdint.h>
+#include <cstring>
+#include <endian.h>
+#include <assert.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+using namespace std;
+
+/** Print tool usage */
+void print_usage();
+
+/** Prepend to a path the img/ subdirectory.
+ *
+ * @param[in,out] io_path - The path to modify / prepend to.
+ */
+void add_image_subdir(string& io_path);
+
+/** Parse the image.modinfo file.
+ *
+ * @param[in] i_image - The path to the image to parse the corresponding
+ * modinfo.
+ */
+void parse_modinfo_file(const string& i_image);
+
+/** Read the symbols from a module.
+ *
+ * @param[in] pair<string, uint64_t>* - Pair of <Path of module, offset >.
+ *
+ * Parameters are passed as a (void*) to allow this function to be started
+ * as a thread.
+ *
+ * @return Unused.
+ */
+void* read_module_symbols(void*);
+
+ /** Module information parsed from modinfo. <Module, Offset> */
+vector<pair<string, uint64_t> > g_modules;
+
+ /** Name / path of the base image. */
+string g_imageName;
+ /** Name / path of the extended image. */
+string g_extImageName;
+ /** Pointer to the mmap of the base image. */
+const char* g_imageFile;
+ /** Size of the base image file. */
+size_t g_imageFileSize;
+ /** Pointer to the mmap of the extended image. */
+const char* g_extImageFile;
+ /** Size of the extended image file. */
+size_t g_extImageFileSize;
+ /** Offset (in memory) that the extended image is to be loaded at. */
+uint64_t g_extImageOffset = ULONG_MAX;
+
+ /** Cached value of the CROSS_PREFIX environment variable, used to
+ * call binutils tools. */
+char* g_crossPrefix = NULL;
+
+ /** Resulting symbol addresses and names.
+ *
+ * This is a multimap because there are some symbol addresses with
+ * multiple names. Ex. the data_start_address often collides with
+ * a global symbol in the data section.
+ */
+multimap<uint64_t, string> g_symbols;
+ /** Mutex to protect symbol map. */
+pthread_mutex_t g_symbolMutex = PTHREAD_MUTEX_INITIALIZER;
+
+int main(int argc, char** argv)
+{
+ // Allow one argument (base image) or three arguments (base, extend, offset)
+ if ((argc != 2) && (argc != 4))
+ {
+ print_usage();
+ }
+
+ // Get base image name.
+ g_imageName = argv[1];
+ add_image_subdir(g_imageName);
+
+ // Get extended image name.
+ if (argc > 3)
+ {
+ g_extImageName = argv[2];
+ add_image_subdir(g_extImageName);
+
+ // Read extended image offset from options.
+ if (1 != sscanf(argv[3], "%lx", &g_extImageOffset))
+ {
+ print_usage();
+ }
+ }
+
+ // Open base image.
+ int base_fd = open(g_imageName.c_str(), O_RDONLY);
+ if (-1 == base_fd)
+ {
+ printf("Failed to open image file: %s.\n", g_imageName.c_str());
+ exit(-1);
+ }
+ struct stat base_stat;
+ if (0 != fstat(base_fd, &base_stat))
+ {
+ printf("Failed to stat image file: %s.\n", g_imageName.c_str());
+ exit(-1);
+ }
+ g_imageFileSize = base_stat.st_size;
+ g_imageFile = (const char*) mmap(NULL, base_stat.st_size,
+ PROT_READ, MAP_PRIVATE,
+ base_fd, 0);
+
+ // Open extended image.
+ if (string() != g_extImageName.c_str())
+ {
+ int ext_fd = open(g_extImageName.c_str(), O_RDONLY);
+ if (-1 == ext_fd)
+ {
+ printf("Failed to open image file: %s.\n", g_extImageName.c_str());
+ exit(-1);
+ }
+ struct stat ext_stat;
+ if (0 != fstat(ext_fd, &ext_stat))
+ {
+ printf("Failed to stat image file: %s.\n", g_extImageName.c_str());
+ exit(-1);
+ }
+ g_extImageFileSize = ext_stat.st_size;
+ g_extImageFile = (const char*) mmap(NULL, ext_stat.st_size,
+ PROT_READ, MAP_PRIVATE,
+ ext_fd, 0);
+ }
+
+ // Read CROSS_PREFIX environment variable.
+ g_crossPrefix = getenv("CROSS_PREFIX");
+ if (NULL == g_crossPrefix)
+ {
+ printf("Environment variable CROSS_PREFIX not set.\n");
+ exit(-1);
+ }
+ g_crossPrefix = strdup(g_crossPrefix);
+
+ // Parse modinfo file for base image.
+ parse_modinfo_file(g_imageName);
+
+ // Create threads for each ELF object in the image(s) to get their symbol
+ // information.
+ vector<pthread_t*> threads;
+ for(vector<pair<string, uint64_t> >::const_iterator i = g_modules.begin();
+ i != g_modules.end(); ++i)
+ {
+ const string& m = i->first;
+ // Filter out non-ELF files by filename.
+ if (strstr(m.c_str(), ".o") || strstr(m.c_str(), ".elf") ||
+ strstr(m.c_str(), ".so"))
+ {
+ pthread_t* thread = new pthread_t;
+ pthread_create(thread, NULL, read_module_symbols,
+ new pair<string,uint64_t>(*i));
+ threads.push_back(thread);
+ }
+ }
+
+ // Wait for all threads to finish.
+ for(vector<pthread_t*>::const_iterator i = threads.begin();
+ i != threads.end(); ++i)
+ {
+ pthread_join(*(*i), NULL);
+ }
+
+ // Output (in order) each symbol information.
+ for (multimap<uint64_t, string>::const_iterator i = g_symbols.begin();
+ i != g_symbols.end(); ++i)
+ {
+ printf("%s", i->second.c_str());
+ }
+
+ return 0;
+}
+
+void print_usage()
+{
+ printf("gensyms <image> [<extimage> <extoffset>]\n");
+ exit(-1);
+}
+
+void add_image_subdir(string& io_path)
+{
+ // Prepend ./img if the path to the image directory is not already part
+ // of the path.
+ if (string::npos == io_path.find("img"))
+ {
+ io_path.insert(0, "./img/");
+ }
+}
+
+void parse_modinfo_file(const string& i_image)
+{
+ // Open modinfo file.
+ string modinfo_name = i_image + ".modinfo";
+ FILE* modinfo_file = fopen(modinfo_name.c_str(), "r");
+ if (NULL == modinfo_file)
+ {
+ printf("Unable to open modinfo file.\n");
+ exit(-1);
+ }
+
+ // Parse one line at a time.
+ char line[1024];
+ do
+ {
+ // fgets returns NULL when no additional lines are present, break.
+ if (NULL == fgets(line, 1024, modinfo_file)) break;
+
+ // Lines should be formatted: "object,offset\n"
+
+ // Skip lines without a comma.
+ char* comma = strchr(line, ',');
+ if (NULL == comma) continue;
+
+ // Extract module name (everything before comma).
+ string mod_name(line, comma - line);
+
+ // Parse module offset (hex integer after comma).
+ uint64_t mod_addr;
+ if (1 != sscanf(comma+1, "0x%lx", &mod_addr)) continue;
+
+ // Add to the module list.
+ g_modules.push_back(make_pair(mod_name, mod_addr));
+
+ } while(1);
+}
+
+void* read_module_symbols(void* input)
+{
+ // Get module name and offset from input parameter.
+ pair<string, uint64_t>* mod_info =
+ reinterpret_cast<pair<string,uint64_t>*>(input);
+ const string& module = mod_info->first;
+ uint64_t addr = mod_info->second;
+
+ // Determine the full path to the module based on the base image path.
+ // Assumes they are in the same subdirectory.
+ string module_path = g_imageName.substr(0, g_imageName.rfind('/') + 1) +
+ module;
+
+ // Create the 'objdump' command for finding all the symbols and start as
+ // a sub-process.
+ string command = string(g_crossPrefix) + string("objdump --syms -C ") +
+ module_path;
+ FILE* pipe = popen(command.c_str(), "r");
+ if (NULL == pipe) return NULL;
+
+ // Local symbol map (to reduce contention on the global symbol map).
+ // No need to use the overhead of a map because we don't care about
+ // order at this point.
+ vector<pair<uint64_t, string> > l_symbols;
+
+ // Parse each line of the 'objdump' output.
+ char line[1024];
+ do
+ {
+ if (NULL == fgets(line, 1024, pipe)) break;
+
+ // Skip absolute values (ex. constants) and undefined symbols.
+ if (strstr(line, "*ABS*") || strstr(line, "*UND*")) continue;
+ // Skip section symbols (marked by 'd' in the 22nd column).
+ if ('d' == line[22]) continue;
+
+ // First part of an objdump line is the symbol address, parse that.
+ uint64_t line_address;
+ if (1 != sscanf(line, "%16lx", &line_address)) continue;
+ line_address += addr;
+
+ // Determine if the symbol is a function and if it is in the .rodata
+ // section. Symbols in the .rodata section have a slightly longer
+ // line than those in the .text/.data sections (by 2 characters).
+ bool is_function = ('F' == line[23]);
+ size_t rodata = (NULL != strstr(line, ".rodata")) ? 2 : 0;
+
+ // Parse the symbol size.
+ uint64_t symbol_size;
+ if (1 != sscanf(&line[32+rodata], "%lx", &symbol_size)) continue;
+
+ // Parse the function name.
+ string function = &line[48+rodata];
+ function.resize(function.length() - 1); // remove the newline.
+
+ // Function have two addresses: TOC entry and code address. Objdump
+ // gives the TOC entry, so we need to read the file itself to determine
+ // the code address. The first part of the TOC entry is the code
+ // address.
+ uint64_t code_addr = 0;
+ if (is_function)
+ {
+ // Module is in the extended image, read from it.
+ if (line_address > g_extImageOffset)
+ {
+ // Read code address.
+ assert((line_address - g_extImageOffset) < g_extImageFileSize);
+ memcpy(&code_addr,
+ &g_extImageFile[line_address - g_extImageOffset], 8);
+ }
+ // Module is in the base image.
+ else
+ {
+ // Read code address.
+ assert(line_address < g_imageFileSize);
+ memcpy(&code_addr, &g_imageFile[line_address], 8);
+ }
+ // Fix up the endianness.
+ code_addr = be64toh(code_addr);
+
+ std::swap(code_addr, line_address);
+ }
+
+ // Print all of this into a new line and add to the symbol map.
+ sprintf(line, "%c,%08lx,%08lx,%08lx,%s\n",
+ is_function ? 'F' : 'V',
+ line_address, code_addr, symbol_size,
+ function.c_str());
+
+ l_symbols.push_back(make_pair(line_address, line));
+
+ } while(1);
+
+ // Close subprocess (done).
+ pclose(pipe);
+
+ // Copy our local symbol list all at once into the global symbol list.
+ pthread_mutex_lock(&g_symbolMutex);
+ g_symbols.insert(l_symbols.begin(), l_symbols.end());
+ pthread_mutex_unlock(&g_symbolMutex);
+
+ return NULL;
+}
diff --git a/src/build/linker/makefile b/src/build/linker/makefile
index 3957cbf6a..1c21bb0cd 100644
--- a/src/build/linker/makefile
+++ b/src/build/linker/makefile
@@ -22,8 +22,8 @@
# IBM_PROLOG_END_TAG
ROOTPATH = ../../..
-CODE_PASS_POST += linker
-CLEAN_TARGETS += linker
+CODE_PASS_POST += linker gensyms
+CLEAN_TARGETS += linker gensyms
include $(ROOTPATH)/config.mk
@@ -32,3 +32,7 @@ linker: linker.C
$(C1)$(CCACHE) $(HOST_PREFIX)g++ -O3 -g linker.C -o linker \
-lbfd -liberty -lz
+gensyms: gensyms.C
+ $(C2) " CXX $(notdir $<)"
+ $(C1)$(CCACHE) $(HOST_PREFIX)g++ -O3 -g gensyms.C -o gensyms \
+ -lpthread
diff --git a/src/build/mkrules/images.rules.mk b/src/build/mkrules/images.rules.mk
index 8c23ec23f..58bb468dd 100644
--- a/src/build/mkrules/images.rules.mk
+++ b/src/build/mkrules/images.rules.mk
@@ -58,7 +58,7 @@ $(IMGDIR)/%.bin: $(IMGDIR)/%.elf \
$(IMGDIR)/%.list.bz2 $(IMGDIR)/%.syms: $(IMGDIR)/%.bin
$(C2) " GENLIST $(notdir $*)"
$(C1)(cd $(ROOTPATH); \
- src/build/tools/gensyms $*.bin $*_extended.bin 0x40000000 \
+ src/build/linker/gensyms $*.bin $*_extended.bin 0x40000000 \
> ./img/$*.syms ; \
src/build/tools/genlist $*.bin | bzip2 -zc > ./img/$*.list.bz2)
diff --git a/src/build/tools/gensyms b/src/build/tools/gensyms
deleted file mode 100755
index 993720045..000000000
--- a/src/build/tools/gensyms
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/usr/bin/perl
-# IBM_PROLOG_BEGIN_TAG
-# This is an automatically generated prolog.
-#
-# $Source: src/build/tools/gensyms $
-#
-# IBM CONFIDENTIAL
-#
-# COPYRIGHT International Business Machines Corp. 2011,2013
-#
-# p1
-#
-# Object Code Only (OCO) source materials
-# Licensed Internal Code Source Materials
-# IBM HostBoot Licensed Internal Code
-#
-# The source code for this program is not published or otherwise
-# divested of its trade secrets, irrespective of what has been
-# deposited with the U.S. Copyright Office.
-#
-# Origin: 30
-#
-# IBM_PROLOG_END_TAG
-
-use strict;
-
-use IO::Seekable;
-
-my $littleendian = (unpack("L", pack("N", 0xabcd1234)) != 0xabcd1234);
-
-sub add_image_subdir
-{
- my $image = shift;
- if (!($image =~ m/\/img/)) { $image = "./img/".$image };
- return $image;
-}
-
-my $image_offset = $ENV{"HAL_IMAGE_OFFSET"};
-if (not $image_offset) { $image_offset = "0x0"; };
-$image_offset = hex $image_offset;
-
-my $image;
-my $extimage;
-my $extoffset;
-my $all_modules = 0;
-my @modules = ();
-
-if ($#ARGV <= 1)
-{
- die "gensyms <image> <extimage> <extoffset> [modules]\n";
-}
-
-if ($#ARGV == 2)
-{
- $all_modules = 1;
-}
-else
-{
- @modules = @ARGV[3..$#ARGV];
-}
-
-my $extoffset = hex $ARGV[2];
-
-$image = add_image_subdir($ARGV[0]);
-open IMAGE, "< $image";
-binmode(IMAGE);
-$extimage = add_image_subdir($ARGV[1]);
-open EXTIMAGE, "< $extimage";
-binmode(EXTIMAGE);
-
-my %module_offsets = ();
-open MODINFO, "< $image.modinfo";
-
-while (my $modline = <MODINFO>)
-{
- chomp $modline;
- my @splitline = split /,/, $modline;
- $module_offsets{@splitline[0]} = (hex @splitline[1]) + $image_offset;
- if ($all_modules)
- {
- push @modules, @splitline[0];
- }
-}
-
-my @output = ();
-foreach my $module (@modules)
-{
- # Only search modules that are likely to be ELF files.
- if (not (($module =~ m/\.o/) or
- ($module =~ m/\.elf/) or
- ($module =~ m/\.so/)))
- {
- next;
- }
-
- my $PREFIX = $ENV{'CROSS_PREFIX'};
- open OBJDUMP, ("${PREFIX}objdump --syms -C ".add_image_subdir($module)."|");
- while (my $line = <OBJDUMP>)
- {
- if (($line =~ m/\*ABS\*/) || ($line =~ m/\*UND\*/))
- {
- next;
- }
- if ("d" eq substr($line, 22, 1))
- {
- next;
- }
- if (!($line =~ m/^[0-9a-f]{16}/))
- {
- next;
- }
-
- $line =~ s/[\s]*$//;
-
- my $address = (hex substr($line, 0, 16)) + $module_offsets{$module};
- my $is_function = ("F" eq substr($line, 23, 1));
- my $size = (hex substr($line, 32, 16));
- my $name = substr($line, 48);
- my $code_loc = 0;
- if ($is_function)
- {
- if (($address - $image_offset) > $extoffset)
- {
- seek EXTIMAGE,
- ($address - ($image_offset + $extoffset)), SEEK_SET;
- read EXTIMAGE, $code_loc, 8;
- }
- else
- {
- seek IMAGE, ($address - $image_offset), SEEK_SET;
- read IMAGE, $code_loc, 8;
- }
- if ($littleendian)
- {
- $code_loc = unpack("Q", reverse($code_loc)) + $image_offset;
- }
- else
- {
- $code_loc = unpack("Q", $code_loc) + $image_offset;
- }
-
- my $tmp = $code_loc; $code_loc = $address; $address = $tmp;
- }
- my $outstring = "";
- $outstring = sprintf "%s,%08x,%08x,%08x,%s\n", ($is_function?"F":"V"),$address,$code_loc,$size,$name;
-
- push @output, $outstring;
- }
- close OBJDUMP;
-}
-
-close IMAGE;
-close EXTIMAGE;
-
-foreach my $outstring (sort { substr($a,2) cmp substr($b,2) } @output)
-{
- print $outstring;
-}
OpenPOWER on IntegriCloud