Refactoring some DWARF parsing to be accessible to StackwalkerAPI
[dyninst.git] / common / h / dwarfExpr.h
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 <stack>
33 #include "dynutil/h/dyn_regs.h"
34 #if !defined(DWARF_EXPR_H)
35 #define DWARF_EXPR_H
36
37 using namespace std;
38 using namespace Dyninst;
39
40 #if defined(arch_x86_64)
41 // We can only safely map the general purpose registers (0-7 on ia-32,
42 // 0-15 on amd-64)
43 #define IA32_MAX_MAP 7
44 #define AMD64_MAX_MAP 15
45 static int const amd64_register_map[] =
46   {
47     0,  // RAX
48     2,  // RDX
49     1,  // RCX
50     3,  // RBX
51     6,  // RSI
52     7,  // RDI
53     5,  // RBP
54     4,  // RSP
55     8, 9, 10, 11, 12, 13, 14, 15    // gp 8 - 15
56     /* This is incomplete. The x86_64 ABI specifies a mapping from
57        dwarf numbers (0-66) to ("architecture number"). Without a
58        corresponding mapping for the SVR4 dwarf-machine encoding for
59        IA-32, however, it is not meaningful to provide this mapping. */
60   };
61
62 int Register_DWARFtoMachineEnc32(int n)
63 {
64   if (n > IA32_MAX_MAP) {
65     dwarf_printf("%s[%d]: unexpected map lookup for DWARF register %d\n",
66                  __FILE__,__LINE__,n);
67   }
68   return n;
69 }
70
71
72 int Register_DWARFtoMachineEnc64(int n)
73 {
74   if (n <= AMD64_MAX_MAP)
75     return amd64_register_map[n];
76   else {
77     dwarf_printf("%s[%d]: unexpected map lookup for DWARF register %d\n",
78                  __FILE__,__LINE__,n);
79     return n;
80   }
81 }
82
83 #define DWARF_TO_MACHINE_ENC(n, proc)                                   \
84   ((proc->getAddressWidth() == 4) ? Register_DWARFtoMachineEnc32((int) n) : Register_DWARFtoMachineEnc64((int) n))
85 #define DWARF_TO_MACHINE_ENC_W(n, w) \
86   (w == 4) ? Register_DWARFtoMachineEnc32((int) n) : Register_DWARFtoMachineEnc64((int) n)
87 #else
88 #define DWARF_TO_MACHINE_ENC(n, proc) (n)
89 #define DWARF_TO_MACHINE_ENC_W(n, w) (n)
90 #endif
91
92 #define DWARF_FALSE_IF(condition,...)           \
93   if ( condition ) { return false; }
94 #define DWARF_RETURN_IF(condition,...)          \
95   if ( condition ) { return; }
96 #define DWARF_NULL_IF(condition,...)            \
97   if ( condition ) { return NULL; }
98 #define DWARF_NEXT_IF(condition, ...)                                   \
99   if (condition) { if (depth != 1) { return false; } else {walk_error = true; break; } }
100
101
102 Dyninst::MachRegister DwarfToDynReg(Dwarf_Signed reg, Dyninst::Architecture arch)
103 {
104    return MachRegister::DwarfEncToReg(reg, arch);
105 }
106
107 Dwarf_Signed DynToDwarfReg(Dyninst::MachRegister reg)
108 {
109    return reg.getDwarfEnc();
110 }
111
112 bool decodeDwarfExpression(Dwarf_Locdesc *dwlocs,
113                            long int *initialStackValue,
114                            VariableLocation *loc, bool &isLocSet,
115                            MemRegReader *reader,
116                            Dyninst::Architecture arch,
117                            long int &end_result)
118 {
119    /* Initialize the stack. */
120    int addr_width = getArchAddressWidth(arch);
121    std::stack< long int > opStack = std::stack<long int>();
122    if ( initialStackValue != NULL ) { opStack.push( * initialStackValue ); }
123
124    Dwarf_Loc *locations = dwlocs->ld_s;
125    unsigned count = dwlocs->ld_cents;
126    for ( unsigned int i = 0; i < count; i++ ) 
127    {
128       /* Handle the literals w/o 32 case statements. */
129       if ( DW_OP_lit0 <= locations[i].lr_atom && locations[i].lr_atom <= DW_OP_lit31 ) 
130       {
131          dwarf_printf( "pushing named constant: %d\n", locations[i].lr_atom - DW_OP_lit0 );
132          opStack.push( locations[i].lr_atom - DW_OP_lit0 );
133          continue;
134       }
135
136       /* Haandle registers w/o 32 case statements. */
137       if ( DW_OP_reg0 <= locations[i].lr_atom && locations[i].lr_atom <= DW_OP_reg31 ) 
138       {
139          /* storageReg is unimplemented, so do an offset of 0 from the named register instead. */
140          dwarf_printf( "location is named register %d\n", 
141                        DWARF_TO_MACHINE_ENC_W(locations[i].lr_atom - DW_OP_reg0, addr_width) );
142          //loc->stClass = storageRegOffset;
143          if (loc) 
144          {
145             loc->stClass = storageReg;
146             loc->refClass = storageNoRef;
147             loc->frameOffset = 0;
148             loc->reg = DWARF_TO_MACHINE_ENC_W(locations[i].lr_atom - DW_OP_reg0, addr_width);
149             //loc->frameOffset = 0;
150             isLocSet = true;
151          }
152          continue;
153       } 
154
155       /* Haandle registers w/o 32 case statements. */
156       if ( DW_OP_breg0 <= locations[i].lr_atom && locations[i].lr_atom <= DW_OP_breg31 ) 
157       {
158          dwarf_printf( "setting storage class to named register, regNum to %d, offset %d\n", DWARF_TO_MACHINE_ENC_W(locations[i].lr_atom - DW_OP_breg0, addr_width), locations[i].lr_number );
159          long int to_push;
160          if (loc) {
161             loc->stClass = storageRegOffset;
162             loc->refClass = storageNoRef;
163             loc->frameOffset = locations[i].lr_number ;
164             loc->reg = DWARF_TO_MACHINE_ENC_W(locations[i].lr_atom - DW_OP_breg0, addr_width);
165             to_push = static_cast<long int>(locations[i].lr_number);
166          }
167          else if (reader) {
168             Dyninst::MachRegister r = DwarfToDynReg(locations[i].lr_atom - DW_OP_breg0,
169                                                     arch);
170             Dyninst::MachRegisterVal v;
171             bool result = reader->GetReg(r, v);
172             if (!result) {
173                return false;
174             }
175             to_push = (long int) v + locations[i].lr_number;
176          }
177             
178          opStack.push(to_push); 
179          continue;
180       }
181
182       switch( locations[i].lr_atom ) 
183       {
184          case DW_OP_addr:
185          case DW_OP_const1u:
186          case DW_OP_const2u:
187          case DW_OP_const4u:
188          case DW_OP_const8u:
189          case DW_OP_constu:
190             dwarf_printf( "pushing unsigned constant %lu\n", 
191                           (unsigned long)locations[i].lr_number );
192             opStack.push(static_cast<long int>(locations[i].lr_number));
193             break;
194
195          case DW_OP_const1s:
196          case DW_OP_const2s:
197          case DW_OP_const4s:
198          case DW_OP_const8s:
199          case DW_OP_consts:
200             dwarf_printf( "pushing signed constant %ld\n", 
201                           (signed long)(locations[i].lr_number) );
202             opStack.push(static_cast<long int>(locations[i].lr_number));
203             break;
204
205          case DW_OP_regx:
206             /* storageReg is unimplemented, so do an offset of 0 from the named register instead. */
207             dwarf_printf( "location is register %d\n", 
208                           DWARF_TO_MACHINE_ENC_W(locations[i].lr_number, addr_width) );
209             if (loc) {
210                loc->stClass = storageReg;
211                loc->refClass = storageNoRef;
212                loc->reg = (int) DWARF_TO_MACHINE_ENC_W(locations[i].lr_number, addr_width); 
213                loc->frameOffset = 0;
214                isLocSet = true;
215             }
216             break;
217
218          case DW_OP_fbreg:
219          {
220             dwarf_printf( "setting storage class to frame base\n" );
221             //if ( storageClass != NULL ) { * storageClass = storageFrameOffset; }
222             long int to_push = 0;
223             if (loc) {
224                loc->stClass = storageRegOffset;
225                loc->refClass = storageNoRef;
226                loc->frameOffset = 0;
227                to_push = static_cast<long int>(locations[i].lr_number);
228             }
229             else if (reader) {
230                Dyninst::MachRegister r = Dyninst::FrameBase;
231                Dyninst::MachRegisterVal v;
232                bool result = reader->GetReg(r, v);
233                if (!result) {
234                   return false;
235                }
236                to_push = (long int) v + locations[i].lr_number;               
237             }
238             opStack.push(to_push);
239          } break;          
240          case DW_OP_bregx: 
241          {
242             dwarf_printf( "setting storage class to register, regNum to %d\n", 
243                           locations[i].lr_number );
244             long int to_push = 0;
245             if (loc) {
246                loc->stClass = storageRegOffset;
247                loc->refClass = storageNoRef;
248                loc->reg = (int) DWARF_TO_MACHINE_ENC_W( locations[i].lr_number, addr_width );
249                loc->frameOffset = 0;
250                to_push = static_cast<long int>(locations[i].lr_number2);
251             }
252             else if (reader) {
253                Dyninst::MachRegister r = DwarfToDynReg(locations[i].lr_number, arch);
254                Dyninst::MachRegisterVal v;
255                bool result = reader->GetReg(r, v);
256                if (!result) {
257                   return false;
258                }
259                to_push = (long int) v + locations[i].lr_number2;
260             }
261             opStack.push(to_push);
262          } break;
263          case DW_OP_dup:
264             DWARF_FALSE_IF( opStack.size() < 1, 
265                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
266             opStack.push( opStack.top() );
267             break;
268
269          case DW_OP_drop:
270             DWARF_FALSE_IF( opStack.size() < 1, 
271                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
272             opStack.pop();
273             break;
274
275          case DW_OP_pick: 
276          {
277             /* Duplicate the entry at index locations[i].lr_number. */
278             std::stack< long int > temp = std::stack< long int >();
279             
280             for ( unsigned int j = 0; j < locations[i].lr_number; j++ ) 
281             {
282                temp.push( opStack.top() ); opStack.pop();
283             }
284             
285             long int dup = opStack.top();
286             
287             for ( unsigned int j = 0; j < locations[i].lr_number; j++ ) 
288             {
289                opStack.push( temp.top() ); temp.pop();
290             }
291             
292             opStack.push( dup );
293          } break;
294
295          case DW_OP_over: 
296          {
297             DWARF_FALSE_IF( opStack.size() < 2, 
298                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
299             long int first = opStack.top(); opStack.pop();
300             long int second = opStack.top(); opStack.pop();
301             opStack.push( second ); opStack.push( first ); opStack.push( second );
302          } break;
303          
304          case DW_OP_swap: 
305          {
306             DWARF_FALSE_IF( opStack.size() < 2, 
307                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
308             long int first = opStack.top(); opStack.pop();
309             long int second = opStack.top(); opStack.pop();
310             opStack.push( first ); opStack.push( second );
311          } break;
312          
313          case DW_OP_deref:
314          {
315             if (!reader)
316                break;
317             long int addr = opStack.top(); opStack.pop();
318             unsigned long to_push = 0;
319             bool bresult = false;
320             if (addr_width == 4) {
321                uint32_t v;
322                bresult = reader->ReadMem(addr, &v, sizeof(v));
323                to_push = (unsigned long) v;
324             }
325             else if (addr_width == 8) {
326                uint64_t v;
327                bresult = reader->ReadMem(addr, &v, sizeof(v));
328                to_push = (unsigned long) v;
329             }
330             DWARF_FALSE_IF(!bresult,
331                            "%s[%d]: Could not read from %lx\n", addr);
332             opStack.push(to_push);
333             break;
334          }
335          case DW_OP_deref_size:
336          {
337             if (!reader)
338                break;
339             long int addr = opStack.top(); opStack.pop();
340             int width = locations[i].lr_number;
341             unsigned long to_push = 0;
342             bool bresult = false;
343             if (width == 1) {
344                uint8_t v;
345                bresult = reader->ReadMem(addr, &v, sizeof(v));
346                to_push = (unsigned long) v;
347             }
348             if (width == 2) {
349                uint16_t v;
350                bresult = reader->ReadMem(addr, &v, sizeof(v));
351                to_push = (unsigned long) v;
352             }
353             if (width == 4) {
354                uint32_t v;
355                bresult = reader->ReadMem(addr, &v, sizeof(v));
356                to_push = (unsigned long) v;
357             }
358             else if (width == 8) {
359                uint64_t v;
360                bresult = reader->ReadMem(addr, &v, sizeof(v));
361                to_push = (long int) v;
362             }
363             DWARF_FALSE_IF(!bresult,
364                            "%s[%d]: Could not read from %lx\n", addr);
365             opStack.push(to_push);
366             break;
367          }
368          case DW_OP_rot: 
369          {
370             DWARF_FALSE_IF( opStack.size() < 3, 
371                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
372             long int first = opStack.top(); opStack.pop();
373             long int second = opStack.top(); opStack.pop();
374             long int third = opStack.top(); opStack.pop();
375             opStack.push( first ); opStack.push( third ); opStack.push( second );
376          } break;
377
378          case DW_OP_abs: 
379          {
380             DWARF_FALSE_IF( opStack.size() < 1, 
381                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
382             long int top = opStack.top(); opStack.pop();
383             opStack.push( abs( top ) );
384          } break;
385          
386          case DW_OP_and: 
387          {
388             DWARF_FALSE_IF( opStack.size() < 2, 
389                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
390             long int first = opStack.top(); opStack.pop();
391             long int second = opStack.top(); opStack.pop();
392             opStack.push( second & first );
393          } break;
394
395          case DW_OP_div: 
396          {
397             DWARF_FALSE_IF( opStack.size() < 2, 
398                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
399             long int first = opStack.top(); opStack.pop();
400             long int second = opStack.top(); opStack.pop();
401             opStack.push( second / first );
402          } break;
403
404          case DW_OP_minus: 
405          {
406             DWARF_FALSE_IF( opStack.size() < 2, 
407                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
408             long int first = opStack.top(); opStack.pop();
409             long int second = opStack.top(); opStack.pop();
410             opStack.push( second - first );
411          } break;
412
413          case DW_OP_mod: 
414          {
415             DWARF_FALSE_IF( opStack.size() < 2, 
416                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
417             long int first = opStack.top(); opStack.pop();
418             long int second = opStack.top(); opStack.pop();
419             opStack.push( second % first );
420          } break;
421
422          case DW_OP_mul: 
423          {
424             DWARF_FALSE_IF( opStack.size() < 2, 
425                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
426             long int first = opStack.top(); opStack.pop();
427             long int second = opStack.top(); opStack.pop();
428             opStack.push( second * first );
429          } break;
430
431          case DW_OP_neg: 
432          {
433             DWARF_FALSE_IF( opStack.size() < 1, 
434                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
435             long int first = opStack.top(); opStack.pop();
436             opStack.push( first * (-1) );
437          } break;
438          
439          case DW_OP_not: 
440          {
441             DWARF_FALSE_IF( opStack.size() < 1, 
442                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
443             long int first = opStack.top(); opStack.pop();
444             opStack.push( ~ first );
445          } break;
446
447          case DW_OP_or: 
448          {
449             DWARF_FALSE_IF( opStack.size() < 2, 
450                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
451             long int first = opStack.top(); opStack.pop();
452             long int second = opStack.top(); opStack.pop();
453             opStack.push( second | first );
454          } break;
455
456          case DW_OP_plus: 
457          {
458             DWARF_FALSE_IF( opStack.size() < 2, 
459                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
460             long int first = opStack.top(); opStack.pop();
461             long int second = opStack.top(); opStack.pop();
462             opStack.push( second + first );
463          } break;
464
465          case DW_OP_plus_uconst: 
466          {
467             DWARF_FALSE_IF( opStack.size() < 1, 
468                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
469             long int first = opStack.top(); opStack.pop();
470             opStack.push(static_cast<long int>(first + locations[i].lr_number));
471          } break;
472          
473          case DW_OP_shl: 
474          {
475             DWARF_FALSE_IF( opStack.size() < 2, 
476                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
477             long int first = opStack.top(); opStack.pop();
478             long int second = opStack.top(); opStack.pop();
479             opStack.push( second << first );
480          } break;
481
482          case DW_OP_shr: 
483          {
484             DWARF_FALSE_IF( opStack.size() < 2, 
485                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
486             long int first = opStack.top(); opStack.pop();
487             long int second = opStack.top(); opStack.pop();
488             
489             opStack.push( (long int)((unsigned long)second >> (unsigned long)first) );
490          } break;
491          
492          case DW_OP_shra: 
493          {
494             DWARF_FALSE_IF( opStack.size() < 2, 
495                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
496             long int first = opStack.top(); opStack.pop();
497             long int second = opStack.top(); opStack.pop();
498             opStack.push( second >> first );
499          } break;
500
501          case DW_OP_xor: 
502          {
503             DWARF_FALSE_IF( opStack.size() < 2, 
504                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
505             long int first = opStack.top(); opStack.pop();
506             long int second = opStack.top(); opStack.pop();
507             opStack.push( second ^ first );
508          } break;
509
510          case DW_OP_le: 
511          {
512             DWARF_FALSE_IF( opStack.size() < 2, 
513                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
514             long int first = opStack.top(); opStack.pop();
515             long int second = opStack.top(); opStack.pop();
516             opStack.push( first <= second ? 1 : 0 );
517          } break;
518
519          case DW_OP_ge: 
520          {
521             DWARF_FALSE_IF( opStack.size() < 2, 
522                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
523             long int first = opStack.top(); opStack.pop();
524             long int second = opStack.top(); opStack.pop();
525             opStack.push( first >= second ? 1 : 0 );
526          } break;
527
528          case DW_OP_eq: 
529          {
530             DWARF_FALSE_IF( opStack.size() < 2, 
531                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
532             long int first = opStack.top(); opStack.pop();
533             long int second = opStack.top(); opStack.pop();
534             opStack.push( first == second ? 1 : 0 );
535          } break;
536
537          case DW_OP_lt: 
538          {
539             DWARF_FALSE_IF( opStack.size() < 2, 
540                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
541             long int first = opStack.top(); opStack.pop();
542             long int second = opStack.top(); opStack.pop();
543             opStack.push( first < second ? 1 : 0 );
544          } break;
545
546          case DW_OP_gt: 
547          {
548             DWARF_FALSE_IF( opStack.size() < 2, 
549                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
550             long int first = opStack.top(); opStack.pop();
551             long int second = opStack.top(); opStack.pop();
552             opStack.push( first > second ? 1 : 0 );
553          } break;
554
555          case DW_OP_ne: 
556          {
557             DWARF_FALSE_IF( opStack.size() < 2, 
558                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
559             long int first = opStack.top(); opStack.pop();
560             long int second = opStack.top(); opStack.pop();
561             opStack.push( first != second ? 1 : 0 );
562          } break;
563
564          case DW_OP_bra:
565          {
566             DWARF_FALSE_IF( opStack.size() < 1, 
567                             "%s[%d]: invalid stack, returning false.\n", __FILE__, __LINE__ );
568             if ( opStack.top() == 0 ) { break; }
569             opStack.pop();
570          }
571          case DW_OP_skip: 
572          {
573             int bytes = (int)(Dwarf_Signed)locations[i].lr_number;
574             unsigned int target = (unsigned int) locations[i].lr_offset + bytes;
575             
576             int j = i;
577             if ( bytes < 0 ) {
578                for ( j = i - 1; j >= 0; j-- ) {
579                   if ( locations[j].lr_offset == target ) { break; }
580                } /* end search backward */
581             } else {
582                for ( j = i + 1; j < dwlocs->ld_cents; j ++ ) {
583                   if ( locations[j].lr_offset == target ) { break; }
584                } /* end search forward */
585             } /* end if positive offset */
586             
587             /* Because i will be incremented the next time around the loop. */
588             i = j - 1;
589          } break;
590
591          case DW_OP_piece:
592             /* For multi-part variables, which we don't handle. */
593             //bperr ( "Warning: dyninst does not handle multi-part variables.\n" );
594             break;
595
596          case DW_OP_nop:
597             break;
598
599          default:
600             dwarf_printf( "Unrecognized or non-static location opcode 0x%x, aborting.\n", locations[i].lr_atom );
601             return false;
602             break;
603       } /* end operand switch */
604    } /* end iteration over Dwarf_Loc entries. */
605    
606    if (opStack.empty()) {
607       dwarf_printf( "ignoring malformed location list (stack empty at end of list).\n" );
608       return isLocSet;
609    }
610    dwarf_printf( "Dwarf expression returning %d\n", opStack.top() );
611    end_result = opStack.top();
612    return true;
613 }
614
615 #endif