Update copyright to LGPL on all files
[dyninst.git] / symtabAPI / src / LineInformation.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "LineInformation.h"
33 #include <assert.h>
34 #include <list>
35 #include <cstring>
36 #include "boost/functional/hash.hpp"
37 #include "common/h/headers.h"
38 #include "Module.h"
39 #include "Serialization.h"
40
41 using namespace Dyninst;
42 using namespace Dyninst::SymtabAPI;
43 using namespace std;
44
45 #if ! defined(os_windows)      
46 struct SourceLineCompare 
47 {
48    bool operator () ( const char * lhs, const char * rhs ) const;
49 };
50
51 typedef dyn_hash_set< const char *, boost::hash< const char * >, SourceLineCompare > SourceLineInternTable;
52
53 #else
54
55 struct SourceLineLess 
56 {
57    bool operator () ( const char * lhs, const char * rhs ) const;
58 };
59
60 typedef std::set< const char *, SourceLineLess > SourceLineInternTable;
61
62 #endif 
63
64 namespace Dyninst {
65 namespace SymtabAPI {
66 class SourceLineInternalTableWrapper {
67    public:
68       SourceLineInternTable source_line_names;
69       SourceLineInternalTableWrapper() {}
70       ~SourceLineInternalTableWrapper(){}
71       SourceLineInternTable &getTable() {return source_line_names;}
72 };
73 }}
74
75 SourceLineInternalTableWrapper *LineInformation::getSourceLineNamesW()
76 {
77    if (sourceLineNamesPtr)
78       return sourceLineNamesPtr;
79
80    sourceLineNamesPtr = new SourceLineInternalTableWrapper();
81
82    if (!sourceLineNamesPtr) 
83       fprintf(stderr, "%s[%d]:  alloc failure here\n", FILE__, __LINE__);
84
85    return sourceLineNamesPtr;
86 }
87
88 SourceLineInternTable &getSourceLineNames(LineInformation *li)
89 {
90    if (!li->sourceLineNamesPtr)
91       li->sourceLineNamesPtr = new SourceLineInternalTableWrapper();
92
93    if (!li->sourceLineNamesPtr)
94    {
95       fprintf(stderr, "%s[%d]:  alloc prob\n", FILE__, __LINE__);
96       abort();
97    }
98
99    return li->sourceLineNamesPtr->getTable();
100 }
101
102 LineInformation::LineInformation() : 
103         AnnotationContainer<Statement>(),
104    Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >(),
105    sourceLineNamesPtr(NULL) 
106 {
107    size_ = 0;
108 } /* end LineInformation constructor */
109
110 bool LineInformation::addItem_impl(Statement s)
111 {
112    size_++;
113
114    bool ret = addValue( s, s.startAddr(), s.endAddr() );
115         return ret;
116 }
117 bool LineInformation::addLine( const char * lineSource, 
118       unsigned int lineNo, 
119       unsigned int lineOffset, 
120       Offset lowInclusiveAddr, 
121       Offset highExclusiveAddr ) 
122 {
123
124    /* If we haven't already, intern the lineSource. */
125    if ( lineSource == NULL ) 
126    { 
127       return false; 
128    }
129
130    const char * lineSourceInternal = NULL;
131    typedef SourceLineInternTable::const_iterator IteratorType;
132    SourceLineInternTable &sourceLineNames = getSourceLineNames(this);
133    IteratorType found = sourceLineNames.find( lineSource );
134
135    if ( found == sourceLineNames.end() ) 
136    {
137       lineSourceInternal = P_strdup( lineSource );
138       assert( lineSourceInternal != NULL );
139       sourceLineNames.insert( lineSourceInternal );
140    }
141    else 
142    {
143       lineSourceInternal = * found;
144    }
145
146    assert( lineSourceInternal != NULL );
147
148    bool ret = addItem_impl( Statement(lineSourceInternal, lineNo, lineOffset, lowInclusiveAddr, highExclusiveAddr)); 
149
150    return ret;
151 } /* end setLineToAddressRangeMapping() */
152
153 void LineInformation::addLineInfo(LineInformation *lineInfo)
154 {
155    const_iterator iter = lineInfo->begin();
156
157    for (; iter != lineInfo->end(); iter++)
158    {
159       addLine(iter->second.file_.c_str(), iter->second.line_, iter->second.column, 
160             iter->first.first, iter->first.second);
161    }
162 }
163
164 bool LineInformation::addAddressRange( Offset lowInclusiveAddr, 
165       Offset highExclusiveAddr, 
166       const char * lineSource, 
167       unsigned int lineNo, 
168       unsigned int lineOffset ) 
169 {
170    return addLine( lineSource, lineNo, lineOffset, lowInclusiveAddr, highExclusiveAddr );
171 } /* end setAddressRangeToLineMapping() */
172
173 bool LineInformation::getSourceLines( Offset addressInRange, 
174       vector< Statement *> & lines ) 
175 {
176    return getValues( addressInRange, lines );
177 } /* end getLinesFromAddress() */
178
179 bool LineInformation::getAddressRanges( const char * lineSource, 
180       unsigned int lineNo, vector< AddressRange > & ranges ) 
181 {
182    bool ret = Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >::getAddressRanges( Statement( lineSource, lineNo ), ranges );
183
184    return ret;
185 } /* end getAddressRangesFromLine() */
186
187 LineInformation::const_iterator LineInformation::begin() const 
188 {
189    return Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >::begin();
190 } /* end begin() */
191
192 LineInformation::const_iterator LineInformation::end() const 
193 {
194    return Dyninst::SymtabAPI::RangeLookup< Statement, Statement::StatementLess >::end();
195 } /* end begin() */
196
197 unsigned LineInformation::getSize() const
198 {
199    return size_;
200 }
201
202 bool Statement::StatementLess::operator () ( const Statement &lhs, const Statement &rhs ) const
203 {
204         //  dont bother with ordering by column information yet.
205
206         int strcmp_res = strcmp( lhs.file_.c_str(), rhs.file_.c_str());
207
208         if (strcmp_res < 0 )
209                 return true;
210
211         if ( strcmp_res == 0 )
212         {
213                 if ( lhs.line_ < rhs.line_ )
214                         return true;
215         }
216
217         return false;
218 } /* end StatementLess() */
219
220 bool Statement::operator==(const Statement &cmp) const 
221 {
222         if (line_ != cmp.line_) return false;
223         if (column != cmp.column) return false;
224
225         //  is compare-by-pointer OK here, or do we really have to really strcmp?
226         return (file_ == cmp.file_);
227 }
228
229
230
231 #if ! defined( os_windows )
232 bool SourceLineCompare::operator () ( const char * lhs, const char * rhs ) const 
233 {
234    return strcmp( lhs, rhs ) == 0;
235 } /* end SourceLineCompare() */
236 #else
237 bool SourceLineLess::operator () ( const char * lhs, const char * rhs ) const 
238 {
239    return strcmp( lhs, rhs ) < 0;
240 } /* end SourceLineLess() */
241 #endif
242
243 /* We free the strings we allocated, and let the compiler clean up everything else:
244
245    Section 10.4.6 [Stroustroup's C++]: "When a class object containing class
246    objects is destroyed, the body of that object's own destructor is executed first,
247    and then the members' destructors are executed in the reverse order of declaration." */
248
249 LineInformation::~LineInformation() 
250 {
251    /* Apparently, the iterator depends on the hash of its current key
252       to continue.  This should probably be cached, to allow me to free
253       the current key if it's a pointer (and the hash over the pointed-to
254       data), but I guess it's not strictly a bug. */
255
256    const char * internedString = NULL;
257    typedef SourceLineInternTable::const_iterator IteratorType;
258    SourceLineInternTable &sourceLineNames = getSourceLineNames(this);
259    SourceLineInternTable::iterator iterator = sourceLineNames.begin();
260
261    while ( iterator != sourceLineNames.end() ) 
262    {
263       internedString = * iterator;
264       ++iterator;
265       free( const_cast< char * >( internedString ) );
266    }    
267
268 } /* end LineInformation destructor */
269
270
271 Serializable *LineInformation::ac_serialize_impl(SerializerBase *sb, const char *tag) THROW_SPEC (SerializerError)
272 {
273    //fprintf(stderr, "%s[%d]:  LineInformation::serialize -- IMPLEMENT ME sb = %p\n", 
274    //      FILE__, __LINE__, sb);
275
276         std::pair<int, int> mypair;
277         std::pair<std::pair<int, int>, int> mypair2;
278
279         ifxml_start_element(sb, tag);
280         //gtranslate(sb, mypair);
281         //gtranslate(sb, mypair2);
282         gtranslate(sb, valuesByAddressRangeMap, "valuesByAddressRangeMap", "valueByAddressRange");
283         gtranslate(sb, addressRangesByValueMap, "addressRangesByValueMap", "addressRangeByValue");
284         gtranslate(sb, size_, "size");
285         //multimap_translator<std::pair<Address, Address>, Statement> mt;
286         //mt(sb, valuesByAddressRangeMap, "valuesByAddressRangeMap", "valueByAddressRange");
287         //translate_multimap(sb, valuesByAddressRangeMap, "valuesByAddressRangeMap", "valueByAddressRange");
288
289         //multimap_translator<std::pair<Address, Address>, Statement>(sb, addressRangesByValueMap, "addressRangesByValueMap", "addressRangeByValue");
290         ifxml_end_element(sb, tag);
291         return NULL;
292
293 }