18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/** 28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file libutil++/op_spu_bfd.cpp 38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Encapsulation of bfd objects for Cell BE SPU 48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2007 OProfile authors 68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING 78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Maynard Johnson 98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * (C) Copyright IBM Corporation 2007 108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <fcntl.h> 148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <sys/stat.h> 158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstdlib> 168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstring> 178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <iostream> 198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstring> 208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstdlib> 218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_bfd.h" 238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "locate_images.h" 248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_libiberty.h" 258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "string_filter.h" 268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "cverb.h" 278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#define OP_SPU_DYN_FLAG 0x10000000 /* kernel module adds this offset */ 298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* to SPU code it can't find in the map */ 308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#define OP_SPU_MEMSIZE 0x3ffff /* Physical memory size on an SPU */ 318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddusing namespace std; 338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddextern verbose vbfd; 358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/* 378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * This overload of the op_bfd constructor is patterned after the 388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * constructor in libutil++/op_bfd.cpp, with the additional processing 398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * needed to handle an embedded spu offset. 408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddop_bfd::op_bfd(uint64_t spu_offset, string const & fname, 428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd string_filter const & symbol_filter, 438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd extra_images const & extra_images, bool & ok) 448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd : 458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd archive_path(extra_images.get_archive_path()), 468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd extra_found_images(extra_images), 478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd file_size(-1), 488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd embedding_filename(fname), 498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd anon_obj(false) 508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{ 518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int fd; 528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd struct stat st; 538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int notes_remaining; 548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd bool spu_note_found = false; 558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd size_t sec_size = 0; 568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned int oct_per_byte; 578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd asection * note = NULL; 588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd symbols_found_t symbols; 608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd asection const * sect; 618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd image_error image_ok; 638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd string const image_path = 648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd extra_images.find_image_path(fname, image_ok, true); 658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "op_bfd ctor for " << image_path << endl; 678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!ok) 688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_fail; 698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd fd = open(image_path.c_str(), O_RDONLY); 718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (fd == -1) { 728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "open failed for " << image_path << endl; 738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ok = false; 748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_fail; 758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (fstat(fd, &st)) { 788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "stat failed for " << image_path << endl; 798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ok = false; 808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_fail; 818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd file_size = st.st_size; 848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ibfd.abfd = spu_open_bfd(image_path, fd, spu_offset); 858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!ibfd.valid()) { 878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "fdopen_bfd failed for " << image_path << endl; 888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ok = false; 898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_fail; 908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* For embedded SPU ELF, a note section named '.note.spu_name' 938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * contains the name of the SPU binary image in the description 948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * field. 958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note = bfd_get_section_by_name(ibfd.abfd, ".note.spu_name"); 978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!note) { 988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "No .note.spu-name section found" << endl; 998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto find_sec_code; 1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "found .note.spu_name section" << endl; 1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd bfd_byte * sec_contents; 1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd oct_per_byte = bfd_octets_per_byte(ibfd.abfd); 1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sec_size = bfd_section_size(ibfd.abfd, note)/oct_per_byte; 1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sec_contents = (bfd_byte *) xmalloc(sec_size); 1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (!bfd_get_section_contents(ibfd.abfd, note, sec_contents, 1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 0, sec_size)) { 1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cverb << vbfd << "bfd_get_section_contents with size " 1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd << sec_size << " returned an error" << endl; 1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ok = false; 1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out_fail; 1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd notes_remaining = sec_size; 1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd while (notes_remaining && !spu_note_found) { 1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd unsigned int nsize, dsize, type; 1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd nsize = *((unsigned int *) sec_contents); 1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd dsize = *((unsigned int *) sec_contents +1); 1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd type = *((unsigned int *) sec_contents +2); 1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int remainder, desc_start, name_pad_length, desc_pad_length; 1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd name_pad_length = desc_pad_length = 0; 1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Calculate padding for 4-byte alignment */ 1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd remainder = nsize % 4; 1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (remainder != 0) 1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd name_pad_length = 4 - remainder; 1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd desc_start = 12 + nsize + name_pad_length; 1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (type != 1) { 1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd int note_record_length; 1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if ((remainder = (dsize % 4)) != 0) 1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd desc_pad_length = 4 - remainder; 1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd note_record_length = 12 + nsize + 1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd name_pad_length + dsize + desc_pad_length; 1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd notes_remaining -= note_record_length; 1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd sec_contents += note_record_length; 1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd continue; 1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } else { 1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd spu_note_found = true; 1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Must memcpy the data from sec_contents to a 1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * 'char *' first, then stringify it, since 1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * the type of sec_contents (bfd_byte *) cannot be 1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * used as input for creating a string. 1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */ 1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd char * description = (char *) xmalloc(dsize); 1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd memcpy(description, sec_contents + desc_start, dsize); 1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd filename = description; 1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd free(description); 1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd free(sec_contents); 1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* Default to app name for the image name */ 1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (spu_note_found == false) 1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd filename = fname; 1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddfind_sec_code: 1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd for (sect = ibfd.abfd->sections; sect; sect = sect->next) { 1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (sect->flags & SEC_CODE) { 1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd if (filepos_map[sect->name] != 0) { 1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd cerr << "Found section \"" << sect->name 1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd << "\" twice for " << get_filename() 1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd << endl; 1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd abort(); 1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd filepos_map[sect->name] = sect->filepos; 1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd } 1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd get_symbols(symbols); 1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* In some cases the SPU library code generates code stubs on the stack. */ 1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd /* The kernel module remaps those addresses so add an entry to catch/report them. */ 1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd symbols.push_back(op_bfd_symbol(OP_SPU_DYN_FLAG, OP_SPU_MEMSIZE, 1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd "__send_to_ppe(stack)")); 1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout: 1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd add_symbols(symbols, symbol_filter); 1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd return; 1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddout_fail: 1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd ibfd.close(); 1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd dbfd.close(); 1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd file_size = -1; 1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd goto out; 1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} 1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd 186