//===--------------------- Unwind_AIXExtras.cpp -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
//===----------------------------------------------------------------------===//

// This file is only used for AIX.
#if defined(_AIX)

#include "config.h"
#include "libunwind_ext.h"
#include <sys/debug.h>

namespace libunwind {
// getFuncNameFromTBTable
// Get the function name from its traceback table.
char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
                             unw_word_t *Offset) {
  uint32_t *p = reinterpret_cast<uint32_t *>(Pc);
  *Offset = 0;

  // Keep looking forward until a word of 0 is found. The traceback
  // table starts at the following word.
  while (*p)
    p++;
  tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);

  if (!TBTable->tb.name_present)
    return NULL;

  // Get to the name of the function.
  p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);

  // Skip field parminfo if it exists.
  if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
    p++;

  // If the tb_offset field exisits, get the offset from the start of
  // the function to pc. Skip the field.
  if (TBTable->tb.has_tboff) {
    unw_word_t StartIp =
        reinterpret_cast<uintptr_t>(TBTable) - *p - sizeof(uint32_t);
    *Offset = Pc - StartIp;
    p++;
  }

  // Skip field hand_mask if it exists.
  if (TBTable->tb.int_hndl)
    p++;

  // Skip fields ctl_info and ctl_info_disp if they exist.
  if (TBTable->tb.has_ctl) {
    p += 1 + *p;
  }

  NameLen = *(reinterpret_cast<uint16_t *>(p));
  return reinterpret_cast<char *>(p) + sizeof(uint16_t);
}
} // namespace libunwind
#endif // defined(_AIX)
