HPCToolkit
ppc64-unwind-interval.c
Go to the documentation of this file.
1 
2 // -*-Mode: C++;-*- // technically C99
3 
4 // * BeginRiceCopyright *****************************************************
5 //
6 // $HeadURL$
7 // $Id$
8 //
9 // --------------------------------------------------------------------------
10 // Part of HPCToolkit (hpctoolkit.org)
11 //
12 // Information about sources of support for research and development of
13 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
14 // --------------------------------------------------------------------------
15 //
16 // Copyright ((c)) 2002-2019, Rice University
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are
21 // met:
22 //
23 // * Redistributions of source code must retain the above copyright
24 // notice, this list of conditions and the following disclaimer.
25 //
26 // * Redistributions in binary form must reproduce the above copyright
27 // notice, this list of conditions and the following disclaimer in the
28 // documentation and/or other materials provided with the distribution.
29 //
30 // * Neither the name of Rice University (RICE) nor the names of its
31 // contributors may be used to endorse or promote products derived from
32 // this software without specific prior written permission.
33 //
34 // This software is provided by RICE and contributors "as is" and any
35 // express or implied warranties, including, but not limited to, the
36 // implied warranties of merchantability and fitness for a particular
37 // purpose are disclaimed. In no event shall RICE or contributors be
38 // liable for any direct, indirect, incidental, special, exemplary, or
39 // consequential damages (including, but not limited to, procurement of
40 // substitute goods or services; loss of use, data, or profits; or
41 // business interruption) however caused and on any theory of liability,
42 // whether in contract, strict liability, or tort (including negligence
43 // or otherwise) arising in any way out of the use of this software, even
44 // if advised of the possibility of such damage.
45 //
46 // ******************************************************* EndRiceCopyright *
47 
48 //***************************************************************************
49 //
50 // HPCToolkit's PPC64 Unwinder
51 //
52 //***************************************************************************
53 
54 //************************* System Include Files ****************************
55 
56 #include <string.h>
57 #include <stdio.h>
58 #include <inttypes.h>
59 #include <assert.h>
60 
61 
62 //*************************** User Include Files ****************************
63 
64 #include <include/gcc-attr.h>
65 #include <include/uint.h>
66 #include <include/min-max.h>
67 #include "ppc64-unwind-interval.h"
68 #include "hpcrun-malloc.h"
69 #include "uw_recipe_map.h"
70 #include "fnbounds_interface.h"
71 #include <hpcrun/hpcrun_stats.h>
72 #include <messages/messages.h>
74 
75 
76 //*************************** Forward Declarations **************************
77 
78 #define MYDBG 0
79 
80 static btuwi_status_t
81 ppc64_build_intervals(char *ins, unsigned int len);
82 
83 static void
85 
86 static const char *
88 
89 static const char *
91 
92 
93 //***************************************************************************
94 // interface operations
95 //***************************************************************************
96 
98 build_intervals(char *ins, unsigned int len, unwinder_t uw)
99 {
100  btuwi_status_t stat = ppc64_build_intervals(ins, len);
101  if (MYDBG) {
103  }
104  return stat;
105 }
106 
107 
108 //***************************************************************************
109 // unwind_interval interface
110 //***************************************************************************
111 
112 // --------------------------------------------------------------------------
113 // Function: new_ui
114 // Purpose:
115 // Allocate and initialize an unwind recipe for a new code address range.
116 // --------------------------------------------------------------------------
118 new_ui(char *startaddr,
119  sp_ty_t sp_ty,
120  ra_ty_t ra_ty,
121  int sp_arg,
122  int ra_arg)
123 {
125  uwi_t *uwi = bitree_uwi_rootval(u);
126 
127  // ----------------------------------------------------------------
128  // Initialize the address range (referred to as an interval) to
129  // which this recipe applies. The interval begins at startaddr.
130  // for now, use 0 as the end address. The end address will be
131  // filled in when a successor recipe is linked behind this one or
132  // when the end of the enclosing routine is reached
133  // ----------------------------------------------------------------
134  uwi->interval.start = (uintptr_t)startaddr;
135  uwi->interval.end = 0;
136 
137  // ----------------------------------------------------------------
138  // initialize the unwind recipe for the given interval as specified
139  // ----------------------------------------------------------------
140  ppc64recipe_t *ppc64recipe = (ppc64recipe_t*) uwi->recipe;
141  ppc64recipe->sp_ty = sp_ty;
142  ppc64recipe->ra_ty = ra_ty;
143  ppc64recipe->sp_arg = sp_arg;
144  ppc64recipe->ra_arg = ra_arg;
145 
146  return u;
147 }
148 
149 
150 void
152 {
153  UWI_END_ADDR(current) = UWI_START_ADDR(next);
154  bitree_uwi_set_rightsubtree(current, next);
155 }
156 
157 
158 /*
159  * Concrete implementation of the abstract val_tostr function of the
160  * generic_val class.
161  * pre-condition: recipe is of type ppc64recipe_t*
162  */
163 void
164 ppc64recipe_tostr(void* recipe, char str[])
165 {
166  // TODO
167  ppc64recipe_t *ppc64recipe = (ppc64recipe_t*)recipe;
168  snprintf(str, MAX_RECIPE_STR, "%s%d",
169  "ppc64recipe sp_ty = ", ppc64recipe->sp_ty);
170 }
171 
172 void
173 ppc64recipe_print(void* recipe)
174 {
175  char str[MAX_RECIPE_STR];
176  ppc64recipe_tostr(recipe, str);
177  printf("%s", str);
178 }
179 
180 
181 /*
182  * concrete implementation of the abstract function for printing an abstract
183  * unwind recipe specified in uw_recipe.h
184  */
185 void
186 uw_recipe_tostr(void* recipe, char str[], unwinder_t uw)
187 {
188  ppc64recipe_tostr(recipe, str);
189 }
190 
191 
192 void
193 uw_recipe_print(void* recipe)
194 {
195  ppc64recipe_print(recipe);
196 }
197 
198 void
200 {
201  if (!u) {
202  return;
203  }
204 
205  printf(" [%p, %p) ty=%-10s,%-10s sp_arg=%5d ra_arg=%5d\n",
206  (void*)UWI_START_ADDR(u), (void*)UWI_END_ADDR(u),
207  sp_ty_string(UWI_RECIPE(u)->sp_ty),
208  ra_ty_string(UWI_RECIPE(u)->ra_ty),
209  UWI_RECIPE(u)->sp_arg, UWI_RECIPE(u)->ra_arg);
210 }
211 
212 
213 //***************************************************************************
214 
215 void
217 {
218  EMSG("suspicous interval for pc = %p", pc);
220 }
221 
222 
223 
224 //***************************************************************************
225 // private operations
226 //***************************************************************************
227 
228 #define STR(s) case s: return #s
229 
230 static const char *
232 {
233  switch (ty) {
234  STR(RATy_NULL);
235  STR(RATy_Reg);
236  STR(RATy_SPRel);
237  default:
238  assert(0);
239  }
240  return NULL;
241 }
242 
243 
244 static const char *
246 {
247  switch (ty) {
248  STR(SPTy_NULL);
249  STR(SPTy_Reg);
250  STR(SPTy_SPRel);
251  default:
252  assert(0);
253  }
254 }
255 
256 
257 #if 0
258 static const char *
259 register_name(int reg)
260 {
261  switch(reg) {
262  case PPC_REG_LR: return "lr";
263  case PPC_REG_R0: return "r0";
264  default: assert(0);
265  }
266  return NULL;
267 }
268 #endif
269 
270 
271 //***************************************************************************
272 // build_intervals: helpers
273 //***************************************************************************
274 
275 static inline bool
276 isInsn_MFLR(uint32_t insn, int* Rt)
277 {
278  if ((insn & PPC_OP_XFX_SPR_MASK) == PPC_OP_MFLR) {
279  *Rt = PPC_OPND_REG_T(insn);
280  return true;
281  }
282  return false;
283 }
284 
285 
286 static inline bool
287 isInsn_MTLR(uint32_t insn, int* Rt)
288 {
289  if ((insn & PPC_OP_XFX_SPR_MASK) == PPC_OP_MTLR) {
290  *Rt = PPC_OPND_REG_T(insn);
291  return true;
292  }
293  return false;
294 }
295 
296 
297 static inline bool
298 isInsn_STW(uint32_t insn, int Rs, int Ra)
299 {
300  const int D = 0x0;
301  return (insn & PPC_INSN_D_MASK) == PPC_INSN_D(PPC_OP_STW, Rs, Ra, D);
302 }
303 
304 
305 static inline bool
306 isInsn_STD(uint32_t insn, int Rs, int Ra)
307 {
308  // std Rs Ra: store Rs at (Ra + D); set Ra to (Ra + D)
309  const int D = 0x0;
310  return (insn & (PPC_INSN_DS_MASK)) == PPC_INSN_DS(PPC_OP_STD, Rs, Ra, D);
311 }
312 
313 
314 static inline bool
315 isInsn_LWZ(uint32_t insn, int Rt, int Ra)
316 {
317  const int D = 0x0;
318  return (insn & PPC_INSN_D_MASK) == PPC_INSN_D(PPC_OP_LWZ, Rt, Ra, D);
319 }
320 
321 
322 static inline bool
323 isInsn_STWU(uint32_t insn, int Rs, int Ra)
324 {
325  // stwu Rs Ra: store Rs at (Ra + D); set Ra to (Ra + D)
326  const int D = 0x0;
327  return (insn & PPC_INSN_D_MASK) == PPC_INSN_D(PPC_OP_STWU, Rs, Ra, D);
328 }
329 
330 
331 static inline bool
332 isInsn_STDU(uint32_t insn, int Rs, int Ra)
333 {
334  // stdu Rs Ra: store Rs at (Ra + D); set Ra to (Ra + D)
335  const int D = 0x0;
336  return (insn & (PPC_INSN_DS_MASK)) == PPC_INSN_DS(PPC_OP_STDU, Rs, Ra, D);
337 }
338 
339 
340 static inline bool
341 isInsn_STWUX(uint32_t insn, int Ra)
342 {
343  // stwux Rs Ra Rb: store Rs at (Ra + Rb); set Ra to (Ra + Rb)
344  const int Rs = 0, Rb = 0, Rc = 0x0;
345  return ((insn & (PPC_OP_X_MASK | PPC_OPND_REG_A_MASK))
346  == PPC_INSN_X(PPC_OP_STWUX, Rs, Ra, Rb, Rc));
347 }
348 
349 static inline bool
350 isInsn_STDUX(uint32_t insn, int Ra)
351 {
352  // stdux Rs Ra Rb: store Rs at (Ra + Rb); set Ra to (Ra + Rb)
353  const int Rs = 0, Rb = 0, Rc = 0x0;
354  return ((insn & (PPC_OP_X_MASK | PPC_OPND_REG_A_MASK))
355  == PPC_INSN_X(PPC_OP_STDUX, Rs, Ra, Rb, Rc));
356 }
357 
358 
359 static inline bool
360 isInsn_ADDI(uint32_t insn, int Rt, int Ra)
361 {
362  const int SI = 0x0;
363  return ((insn & PPC_INSN_D_MASK) == PPC_INSN_D(PPC_OP_ADDI, Rt, Ra, SI));
364 }
365 
366 
367 static inline bool
368 isInsn_MR(uint32_t insn, int Ra)
369 {
370  // mr Ra Rs = or Ra Rs Rb where Rs = Rb
371  const int Rs = 0, Rc = 0x0;
372  bool isMoveToRa = ((insn & (PPC_OP_X_MASK | PPC_OPND_REG_A_MASK))
373  == PPC_INSN_X(PPC_OP_MR, Rs, Ra, Rs, Rc));
374  bool isRsEqRb = (PPC_OPND_REG_S(insn) == PPC_OPND_REG_B(insn));
375  return (isMoveToRa && isRsEqRb);
376 }
377 
378 
379 static inline bool
380 isInsn_BLR(uint32_t insn)
381 {
382  return (insn == PPC_OP_BLR);
383 }
384 
385 
386 //***************************************************************************
387 
388 static inline int
389 getRADispFromSPDisp(int sp_disp)
390 {
391 #ifdef __PPC64__
392  int disp = sp_disp + 2 * (sizeof(void*));
393 #else
394  int disp = sp_disp + (sizeof(void*));
395 #endif
396  return disp;
397 }
398 
399 
400 static inline int
402 {
403  // if sp_ty != SPTy_SPRel, then frame size is 0
404  return (UWI_RECIPE(ui)->sp_ty == SPTy_SPRel) ? UWI_RECIPE(ui)->sp_arg : 0;
405 }
406 
407 
408 #define INSN(insn) ((char*)(insn))
409 static inline char*
410 nextInsn(uint32_t* insn)
411 {
412  return INSN(insn + 1);
413 }
414 
415 
416 //***************************************************************************
417 // build_intervals:
418 //***************************************************************************
419 
420 // R1 (almost) invariably remains the stack pointer, even for dynamically
421 // sized frames or very large frames. Moreover, every non-leaf procedure
422 // stores the SP using stwu/stwux, creating a linked list of SPs.
423 //
424 // Exception: sometimes R1 appears to be updated non-atomically (i.e., without
425 // a variant of stwu):
426 // lwz r0,0(r1) [load parent-SP, located at SP/r1]
427 // mr r1,r3 [clobber SP]
428 // stw r0,0(r3) [save parent-SP at r3, making SP valid!] <-- sample!
429 //
430 // PPC frame layout:
431 //
432 // bottom (outermost frame)
433 // |-------------|
434 // A| |
435 // | RA | <- stored by caller
436 // | CR | (64-bit ABI only)
437 // | SP <--- | <- stored w/ stwu
438 // |--------/----|
439 // B| / | Typical frame
440 // | RA / | <- (by C)
441 // | CR / | (64-bit ABI only)
442 // | SP / <- <- | <- (stwu)
443 // |-------/--|--|
444 // C| / | | Possible nasty frame
445 // | [] / | | <-
446 // | SP / / | <- (stwu)
447 // |- - - - / - -|
448 // | / | (xtra frame)
449 // | / |
450 // | / |
451 // | SP / | <- stwux
452 // |-------------|
453 
454 
455 // Typical PPC frames (constant frame size <= 16 bits)
456 // stwu r1, -32(r1) ! store with update: store SP (r1) at -32(r1)
457 // and *then* set SP (r1) to -32(r1)
458 // mflr r0 ! move from LR: (and store into RA/r0)
459 // stw r0, 36(r1) ! store word: store RA (r0) in *parent* frame
460 //
461 // ... compute ...
462 //
463 // lwz r0, 36(r1) ! load LR
464 // mtlr r0 ! mtlr: move to LR (from r0)
465 // blr ! blr: return!
466 //
467 // States:
468 // 1. RA is in register (LR/r0); SP (r1) points to parent's frame
469 // 2. RA is in register (LR/r0); SP (r1) has been stored & updated
470 // 3. RA is SP-relative ; SP (r1) has been stored & updated
471 
472 
473 // Nasty PPC frames have few common characteristics between compilers
474 // (frame size > 16 bit displacement field)
475 // mflr r0
476 // mr r12,r1 !
477 // stw r0,4(r1) ! save RA in parent frame (note frame size is 0)
478 // lis r0,-1 ! r0 <- 0xffff0000 (-65536)
479 // addic r0,r0,-1664 ! r0 <- 67200 = -65536 + -1664
480 // stwux r1,r1,r0 ! store r1 at (r1 + r0); set r1 to (r1 + r0)
481 //
482 // ... compute: cobber r12, of course! ...
483 //
484 // addis r11,r1,1 ! r11 <- r1 + [0x10000 (65536)]
485 // addi r11,r11,1664 ! r11 <- r11 + 1664
486 // lwz r0,4(r11) ! restore RA (r0)
487 // mr r1,r11 ! restore SP (r1)
488 // mtlr r0
489 // blr
490 
491 // flash: runtimeparameters_read (above)
492 // flash: <_ZN4DCMF7MappingC2ERNS_11PersonalityERNS_13MemoryManagerERNS_3Log3LogE>:
493 // lis r0,-3
494 // mr r12,r1
495 // ori r0,r0,49040
496 // stwux r1,r1,r0
497 // mflr r0
498 // stw r0,4(r12)
499 // ...
500 // lwz r11,0(r1)
501 // lwz r0,4(r11)
502 // mtlr r0
503 // mr r1,r11
504 
505 // Another nasty frame now in t1:
506 
507 
508 static btuwi_status_t
509 ppc64_build_intervals(char *beg_insn, unsigned int len)
510 {
511  unwind_interval* beg_ui =
513  unwind_interval* ui = beg_ui;
514  unwind_interval* canon_ui = beg_ui;
515  int count = 1;
516 
517  uint32_t* cur_insn = (uint32_t*) beg_insn;
518  uint32_t* end_insn = (uint32_t*) (beg_insn + len);
519 
520  int reg;
521 
522  while (cur_insn < end_insn) {
523  unwind_interval* prev_ui = ui;
524  unwind_interval* nxt_ui = NULL;
525 
526  //TMSG(INTV, "insn: 0x%x [%p,%p)", *cur_insn, cur_insn, end_insn);
527 
528  //--------------------------------------------------
529  // move return address from LR (to 'reg')
530  //--------------------------------------------------
531  if (UWI_RECIPE(ui)->ra_ty == RATy_Reg &&
532  UWI_RECIPE(ui)->ra_arg == PPC_REG_LR &&
533  isInsn_MFLR(*cur_insn, &reg)) {
534  nxt_ui =
535  new_ui(nextInsn(cur_insn), UWI_RECIPE(ui)->sp_ty, RATy_Reg,
536  UWI_RECIPE(ui)->sp_arg, reg);
537  ui = nxt_ui;
538  }
539  //--------------------------------------------------
540  // move return address to LR (from 'reg')
541  //--------------------------------------------------
542  else if (isInsn_MTLR(*cur_insn, &reg)) {
543  // TODO: could scan backwards based on 'reg' (e.g., isInsn_LWZ)
544  nxt_ui =
545  new_ui(nextInsn(cur_insn), UWI_RECIPE(ui)->sp_ty, RATy_Reg,
546  UWI_RECIPE(ui)->sp_arg, PPC_REG_LR);
547  ui = nxt_ui;
548  }
549  //--------------------------------------------------
550  // store return address into parent's frame
551  // (may come before or after frame allocation)
552  //--------------------------------------------------
553  else if (UWI_RECIPE(ui)->ra_ty == RATy_Reg &&
554  UWI_RECIPE(ui)->ra_arg >= PPC_REG_R0 &&
555  isInsn_STW(*cur_insn, UWI_RECIPE(ui)->ra_arg, PPC_REG_SP)) {
556  int sp_disp = getSPDispFromUI(ui);
557  int ra_disp = PPC_OPND_DISP(*cur_insn);
558  if (getRADispFromSPDisp(sp_disp) == ra_disp) {
559  nxt_ui =
560  new_ui(nextInsn(cur_insn), UWI_RECIPE(ui)->sp_ty, RATy_SPRel,
561  UWI_RECIPE(ui)->sp_arg, ra_disp);
562  ui = nxt_ui;
563 
564  canon_ui = nxt_ui;
565  }
566  }
567  //--------------------------------------------------
568  // store return address into parent's frame
569  // (may come before or after frame allocation)
570  //--------------------------------------------------
571  else if (UWI_RECIPE(ui)->ra_ty == RATy_Reg &&
572  UWI_RECIPE(ui)->ra_arg >= PPC_REG_R0 &&
573  isInsn_STD(*cur_insn, UWI_RECIPE(ui)->ra_arg, PPC_REG_SP)) {
574  int sp_disp = getSPDispFromUI(ui);
575  int ra_disp = PPC_OPND_DISP_DS(*cur_insn);
576  if (getRADispFromSPDisp(sp_disp) == ra_disp) {
577  nxt_ui =
578  new_ui(nextInsn(cur_insn), UWI_RECIPE(ui)->sp_ty, RATy_SPRel,
579  UWI_RECIPE(ui)->sp_arg, ra_disp);
580  ui = nxt_ui;
581 
582  canon_ui = nxt_ui;
583  }
584  }
585  //--------------------------------------------------
586  // load return address from caller's frame (into R0)
587  //--------------------------------------------------
588  else if (isInsn_LWZ(*cur_insn, PPC_REG_RA, PPC_REG_SP)) {
589  int sp_disp = getSPDispFromUI(ui);
590  int ra_disp = PPC_OPND_DISP(*cur_insn);
591  if (getRADispFromSPDisp(sp_disp) == ra_disp) {
592  nxt_ui =
593  new_ui(nextInsn(cur_insn), UWI_RECIPE(ui)->sp_ty, RATy_Reg,
594  UWI_RECIPE(ui)->sp_arg, PPC_REG_R0);
595  ui = nxt_ui;
596  }
597  }
598  //--------------------------------------------------
599  // allocate frame: adjust SP and store parent's SP
600  // (may come before or after storing of RA)
601  //--------------------------------------------------
602  else if (isInsn_STWU(*cur_insn, PPC_REG_SP, PPC_REG_SP)) {
603  int sp_disp = - PPC_OPND_DISP(*cur_insn);
604  int ra_arg = ((UWI_RECIPE(ui)->ra_ty == RATy_SPRel) ?
605  UWI_RECIPE(ui)->ra_arg + sp_disp : UWI_RECIPE(ui)->ra_arg);
606  nxt_ui =
607  new_ui(nextInsn(cur_insn), SPTy_SPRel, UWI_RECIPE(ui)->ra_ty,
608  sp_disp, ra_arg);
609  ui = nxt_ui;
610 
611  canon_ui = nxt_ui;
612  }
613  //--------------------------------------------------
614  // allocate frame: adjust SP and store parent's SP
615  // (may come before or after storing of RA)
616  //--------------------------------------------------
617  else if (isInsn_STDU(*cur_insn, PPC_REG_SP, PPC_REG_SP)) {
618  int sp_disp = - PPC_OPND_DISP_DS(*cur_insn);
619  int ra_arg = ((UWI_RECIPE(ui)->ra_ty == RATy_SPRel) ?
620  UWI_RECIPE(ui)->ra_arg + sp_disp : UWI_RECIPE(ui)->ra_arg);
621  nxt_ui =
622  new_ui(nextInsn(cur_insn), SPTy_SPRel, UWI_RECIPE(ui)->ra_ty,
623  sp_disp, ra_arg);
624  ui = nxt_ui;
625 
626  canon_ui = nxt_ui;
627  }
628  else if (isInsn_STWUX(*cur_insn, PPC_REG_SP)) {
629  int sp_disp = -1; // N.B. currently we do not track this
630  nxt_ui =
631  new_ui(nextInsn(cur_insn),SPTy_SPRel, UWI_RECIPE(ui)->ra_ty,
632  sp_disp, UWI_RECIPE(ui)->ra_arg);
633  ui = nxt_ui;
634 
635  canon_ui = nxt_ui;
636  }
637  else if (isInsn_STDUX(*cur_insn, PPC_REG_SP)) {
638  int sp_disp = -1; // N.B. currently we do not track this
639  nxt_ui =
640  new_ui(nextInsn(cur_insn), SPTy_SPRel, UWI_RECIPE(ui)->ra_ty,
641  sp_disp, UWI_RECIPE(ui)->ra_arg);
642  ui = nxt_ui;
643 
644  canon_ui = nxt_ui;
645  }
646  //--------------------------------------------------
647  // deallocate frame: reset SP to parents's SP
648  //--------------------------------------------------
649  else if (isInsn_ADDI(*cur_insn, PPC_REG_SP, PPC_REG_SP)
650  && (PPC_OPND_DISP(*cur_insn) == getSPDispFromUI(ui))) {
651  int sp_disp = - PPC_OPND_DISP(*cur_insn);
652  int ra_arg = ((UWI_RECIPE(ui)->ra_ty == RATy_SPRel) ?
653  UWI_RECIPE(ui)->ra_arg + sp_disp : UWI_RECIPE(ui)->ra_arg);
654  nxt_ui =
655  new_ui(nextInsn(cur_insn), SPTy_Reg, UWI_RECIPE(ui)->ra_ty,
656  PPC_REG_SP, ra_arg);
657  ui = nxt_ui;
658  }
659  else if (isInsn_MR(*cur_insn, PPC_REG_SP)) {
660  // N.B. To be sure the MR restores SP, we would have to track
661  // registers. As a sanity check, test for a non-zero frame size
662  if (getSPDispFromUI(ui) != 0) {
663  nxt_ui =
664  new_ui(nextInsn(cur_insn), SPTy_Reg, UWI_RECIPE(ui)->ra_ty,
665  PPC_REG_SP, UWI_RECIPE(ui)->ra_arg);
666  ui = nxt_ui;
667  }
668  }
669  //--------------------------------------------------
670  // interior returns/epilogues
671  //--------------------------------------------------
672  else if (isInsn_BLR(*cur_insn) && (cur_insn + 1 < end_insn)) {
673  // TODO: ensure that frame has been deallocated and mtlr issued
674  // and adjust intervals if necessary.
675 
676  // An interior return. Restore the canonical interval if necessary.
677  if (!ui_cmp(ui, canon_ui)) {
678  nxt_ui =
679  new_ui(nextInsn(cur_insn), UWI_RECIPE(canon_ui)->sp_ty, UWI_RECIPE(canon_ui)->ra_ty,
680  UWI_RECIPE(canon_ui)->sp_arg, UWI_RECIPE(canon_ui)->ra_arg);
681  ui = nxt_ui;
682  }
683  }
684 
685  if (prev_ui != ui) {
686  link_ui(prev_ui, ui);
687  count++;
688  }
689 
690  cur_insn++;
691  }
692 
693  UWI_END_ADDR(ui) = end_insn;
694 
695  btuwi_status_t stat;
696  stat.first_undecoded_ins = NULL;
697  stat.count = count;
698  stat.error = 0;
699  stat.first = beg_ui;
700 
701  return stat;
702 }
703 
704 
705 static void
707 {
708  TMSG(INTV, "");
709  for (unwind_interval* u = beg_ui; u; u = UWI_NEXT(u)) {
710  ui_dump(u);
711  }
712  TMSG(INTV, "");
713 }
714 
715 
716 void
718 {
719  void *s, *e;
721 
722  fnbounds_enclosing_addr(addr, &s, &e, NULL);
723 
724  uintptr_t llen = ((uintptr_t)e) - (uintptr_t)s;
725 
726  printf("build intervals from %p to %p (%"PRIuPTR")\n", s, e, llen);
727  intervals = ppc64_build_intervals(s, (unsigned int) llen); // TODO: shelf hcprun_ui_malloc for now, as in x86_dump_intervals
728 
730 }
731 
732 
733 void
735 {
736  ppc64_dump_intervals(addr);
737 }
void uw_recipe_print(void *recipe)
#define PPC_OP_XFX_SPR_MASK
bitree_uwi_t * first
static bool isInsn_MTLR(uint32_t insn, int *Rt)
#define PPC_OP_MFLR
#define PPC_REG_RA
void link_ui(unwind_interval *current, unwind_interval *next)
#define PPC_OP_STWU
void hpcrun_dump_intervals(void *addr)
void suspicious_interval(void *pc)
uwi_t * bitree_uwi_rootval(bitree_uwi_t *tree)
#define PPC_OP_X_MASK
#define PPC_OP_LWZ
char * first_undecoded_ins
static bool isInsn_ADDI(uint32_t insn, int Rt, int Ra)
#define PPC_OP_STDU
#define PPC_OPND_DISP(x)
#define PPC_OPND_REG_B(insn)
void uw_recipe_tostr(void *recipe, char str[], unwinder_t uw)
#define PPC_OP_MTLR
uintptr_t end
Definition: interval_t.h:28
static void ppc64_print_interval_set(unwind_interval *first)
static bool isInsn_STWU(uint32_t insn, int Rs, int Ra)
static bool ui_cmp(unwind_interval *ux, unwind_interval *uy)
#define UWI_RECIPE(btuwi)
static bool isInsn_LWZ(uint32_t insn, int Rt, int Ra)
#define PPC_OPND_REG_T(insn)
bitree_uwi_t * bitree_uwi_malloc(unwinder_t uw, size_t recipe_size)
interval_t interval
static bool isInsn_STWUX(uint32_t insn, int Ra)
#define PPC_OP_STW
#define PPC_REG_R0
static int getRADispFromSPDisp(int sp_disp)
#define PPC_OP_STWUX
static const char * ra_ty_string(ra_ty_t ty)
#define EMSG
Definition: messages.h:70
#define PPC_OPND_DISP_DS(x)
static btuwi_status_t ppc64_build_intervals(char *ins, unsigned int len)
#define PPC_OP_BLR
void ppc64recipe_print(void *recipe)
static char * nextInsn(uint32_t *insn)
static bool isInsn_BLR(uint32_t insn)
struct bitree_uwi_s bitree_uwi_t
static bool isInsn_STDUX(uint32_t insn, int Ra)
void ppc64recipe_tostr(void *recipe, char str[])
static int getSPDispFromUI(unwind_interval *ui)
unwind_interval * new_ui(char *startaddr, sp_ty_t sp_ty, ra_ty_t ra_ty, int sp_arg, int ra_arg)
#define MAX_RECIPE_STR
#define PPC_INSN_D(opc, RS, RA, D)
#define UWI_NEXT(btuwi)
#define PPC_OP_STDUX
static bool isInsn_STW(uint32_t insn, int Rs, int Ra)
static bool isInsn_MR(uint32_t insn, int Ra)
#define TMSG(f,...)
Definition: messages.h:93
static bool isInsn_STDU(uint32_t insn, int Rs, int Ra)
#define UWI_END_ADDR(btuwi)
#define PPC_OP_MR
#define MYDBG
#define INSN(insn)
char recipe[]
#define PPC_REG_SP
void ui_dump(unwind_interval *u)
static bool isInsn_MFLR(uint32_t insn, int *Rt)
#define UWI_START_ADDR(btuwi)
#define NULL
Definition: ElfHelper.cpp:85
#define PPC_INSN_D_MASK
#define PPC_REG_LR
#define PPC_OP_ADDI
bitree_uwi_t unwind_interval
enum unwinder_e unwinder_t
#define STR(s)
#define PPC_INSN_DS_MASK
btuwi_status_t build_intervals(char *ins, unsigned int len, unwinder_t uw)
#define PPC_OPND_REG_A_MASK
#define PPC_OPND_REG_S(insn)
uintptr_t start
Definition: interval_t.h:27
void hpcrun_stats_num_unwind_intervals_suspicious_inc(void)
Definition: hpcrun_stats.c:258
cct_addr_t * addr
Definition: cct.c:130
#define PPC_INSN_X(opc, RS, RA, RB, Rc)
static bool isInsn_STD(uint32_t insn, int Rs, int Ra)
static const char * sp_ty_string(sp_ty_t ty)
void ppc64_dump_intervals(void *addr)
#define PPC_OP_STD
#define PPC_INSN_DS(opc, RS, RA, D)
void bitree_uwi_set_rightsubtree(bitree_uwi_t *tree, bitree_uwi_t *subtree)
bool fnbounds_enclosing_addr(void *ip, void **start, void **end, load_module_t **lm)