232 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2010 Google Inc. All Rights Reserved.
 | |
| //
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are
 | |
| // met:
 | |
| //
 | |
| //     * Redistributions of source code must retain the above copyright
 | |
| // notice, this list of conditions and the following disclaimer.
 | |
| //     * Redistributions in binary form must reproduce the above
 | |
| // copyright notice, this list of conditions and the following disclaimer
 | |
| // in the documentation and/or other materials provided with the
 | |
| // distribution.
 | |
| //     * Neither the name of Google Inc. nor the names of its
 | |
| // contributors may be used to endorse or promote products derived from
 | |
| // this software without specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| // This is a client for the dwarf2reader to extract function and line
 | |
| // information from the debug info.
 | |
| 
 | |
| #include <assert.h>
 | |
| #include <limits.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include <map>
 | |
| #include <queue>
 | |
| #include <vector>
 | |
| 
 | |
| #include "common/dwarf/functioninfo.h"
 | |
| #include "common/dwarf/bytereader.h"
 | |
| #include "common/scoped_ptr.h"
 | |
| #include "common/using_std_string.h"
 | |
| 
 | |
| using google_breakpad::scoped_ptr;
 | |
| 
 | |
| namespace dwarf2reader {
 | |
| 
 | |
| CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
 | |
|                                      std::vector<string>* dirs,
 | |
|                                      LineMap* linemap):linemap_(linemap),
 | |
|                                                        files_(files),
 | |
|                                                        dirs_(dirs) {
 | |
|   // The dirs and files are 1 indexed, so just make sure we put
 | |
|   // nothing in the 0 vector.
 | |
|   assert(dirs->size() == 0);
 | |
|   assert(files->size() == 0);
 | |
|   dirs->push_back("");
 | |
|   SourceFileInfo s;
 | |
|   s.name = "";
 | |
|   s.lowpc = ULLONG_MAX;
 | |
|   files->push_back(s);
 | |
| }
 | |
| 
 | |
| void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) {
 | |
|   // These should never come out of order, actually
 | |
|   assert(dir_num == dirs_->size());
 | |
|   dirs_->push_back(name);
 | |
| }
 | |
| 
 | |
| void CULineInfoHandler::DefineFile(const string& name,
 | |
|                                    int32 file_num, uint32 dir_num,
 | |
|                                    uint64 mod_time, uint64 length) {
 | |
|   assert(dir_num >= 0);
 | |
|   assert(dir_num < dirs_->size());
 | |
| 
 | |
|   // These should never come out of order, actually.
 | |
|   if (file_num == (int32)files_->size() || file_num == -1) {
 | |
|     string dir = dirs_->at(dir_num);
 | |
| 
 | |
|     SourceFileInfo s;
 | |
|     s.lowpc = ULLONG_MAX;
 | |
| 
 | |
|     if (dir == "") {
 | |
|       s.name = name;
 | |
|     } else {
 | |
|       s.name = dir + "/" + name;
 | |
|     }
 | |
| 
 | |
|     files_->push_back(s);
 | |
|   } else {
 | |
|     fprintf(stderr, "error in DefineFile");
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num,
 | |
|                                 uint32 line_num, uint32 column_num) {
 | |
|   if (file_num < files_->size()) {
 | |
|     linemap_->insert(
 | |
|         std::make_pair(address,
 | |
|                        std::make_pair(files_->at(file_num).name.c_str(),
 | |
|                                       line_num)));
 | |
| 
 | |
|     if (address < files_->at(file_num).lowpc) {
 | |
|       files_->at(file_num).lowpc = address;
 | |
|     }
 | |
|   } else {
 | |
|     fprintf(stderr, "error in AddLine");
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset,
 | |
|                                                  uint8 address_size,
 | |
|                                                  uint8 offset_size,
 | |
|                                                  uint64 cu_length,
 | |
|                                                  uint8 dwarf_version) {
 | |
|   current_compilation_unit_offset_ = offset;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| // For function info, we only care about subprograms and inlined
 | |
| // subroutines. For line info, the DW_AT_stmt_list lives in the
 | |
| // compile unit tag.
 | |
| 
 | |
| bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) {
 | |
|   switch (tag) {
 | |
|     case DW_TAG_subprogram:
 | |
|     case DW_TAG_inlined_subroutine: {
 | |
|       current_function_info_ = new FunctionInfo;
 | |
|       current_function_info_->lowpc = current_function_info_->highpc = 0;
 | |
|       current_function_info_->name = "";
 | |
|       current_function_info_->line = 0;
 | |
|       current_function_info_->file = "";
 | |
|       offset_to_funcinfo_->insert(std::make_pair(offset,
 | |
|                                                  current_function_info_));
 | |
|     };
 | |
|       // FALLTHROUGH
 | |
|     case DW_TAG_compile_unit:
 | |
|       return true;
 | |
|     default:
 | |
|       return false;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| // Only care about the name attribute for functions
 | |
| 
 | |
| void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset,
 | |
|                                                    enum DwarfAttribute attr,
 | |
|                                                    enum DwarfForm form,
 | |
|                                                    const string &data) {
 | |
|   if (current_function_info_) {
 | |
|     if (attr == DW_AT_name)
 | |
|       current_function_info_->name = data;
 | |
|     else if (attr == DW_AT_MIPS_linkage_name)
 | |
|       current_function_info_->mangled_name = data;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
 | |
|                                                      enum DwarfAttribute attr,
 | |
|                                                      enum DwarfForm form,
 | |
|                                                      uint64 data) {
 | |
|   if (attr == DW_AT_stmt_list) {
 | |
|     SectionMap::const_iterator iter = sections_.find("__debug_line");
 | |
|     assert(iter != sections_.end());
 | |
| 
 | |
|     scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
 | |
|                                                iter->second.second  - data,
 | |
|                                                reader_, linehandler_));
 | |
|     lireader->Start();
 | |
|   } else if (current_function_info_) {
 | |
|     switch (attr) {
 | |
|       case DW_AT_low_pc:
 | |
|         current_function_info_->lowpc = data;
 | |
|         break;
 | |
|       case DW_AT_high_pc:
 | |
|         current_function_info_->highpc = data;
 | |
|         break;
 | |
|       case DW_AT_decl_line:
 | |
|         current_function_info_->line = data;
 | |
|         break;
 | |
|       case DW_AT_decl_file:
 | |
|         current_function_info_->file = files_->at(data).name;
 | |
|         break;
 | |
|       default:
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset,
 | |
|                                                       enum DwarfAttribute attr,
 | |
|                                                       enum DwarfForm form,
 | |
|                                                       uint64 data) {
 | |
|   if (current_function_info_) {
 | |
|     switch (attr) {
 | |
|       case DW_AT_specification: {
 | |
|         // Some functions have a "specification" attribute
 | |
|         // which means they were defined elsewhere. The name
 | |
|         // attribute is not repeated, and must be taken from
 | |
|         // the specification DIE. Here we'll assume that
 | |
|         // any DIE referenced in this manner will already have
 | |
|         // been seen, but that's not really required by the spec.
 | |
|         FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
 | |
|         if (iter != offset_to_funcinfo_->end()) {
 | |
|           current_function_info_->name = iter->second->name;
 | |
|           current_function_info_->mangled_name = iter->second->mangled_name;
 | |
|         } else {
 | |
|           // If you hit this, this code probably needs to be rewritten.
 | |
|           fprintf(stderr,
 | |
|                   "Error: DW_AT_specification was seen before the referenced "
 | |
|                   "DIE! (Looking for DIE at offset %08llx, in DIE at "
 | |
|                   "offset %08llx)\n", data, offset);
 | |
|         }
 | |
|         break;
 | |
|       }
 | |
|       default:
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CUFunctionInfoHandler::EndDIE(uint64 offset) {
 | |
|   if (current_function_info_ && current_function_info_->lowpc)
 | |
|     address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
 | |
|                                                 current_function_info_));
 | |
| }
 | |
| 
 | |
| }  // namespace dwarf2reader
 |