<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2018 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <execinfo.h>
#include <stdio.h>
#include <string.h>
#include <map>
#include <vector>
#include "os/os_specific.h"

void *renderdocBase = NULL;
void *renderdocEnd = NULL;

class LinuxCallstack : public Callstack::Stackwalk
{
public:
  LinuxCallstack()
  {
    RDCEraseEl(addrs);
    numLevels = 0;
    Collect();
  }
  LinuxCallstack(uint64_t *calls, size_t num) { Set(calls, num); }
  ~LinuxCallstack() {}
  void Set(uint64_t *calls, size_t num)
  {
    numLevels = num;
    for(int i = 0; i < numLevels; i++)
      addrs[i] = calls[i];
  }

  size_t NumLevels() const { return size_t(numLevels); }
  const uint64_t *GetAddrs() const { return addrs; }
private:
  LinuxCallstack(const Callstack::Stackwalk &other);

  void Collect()
  {
    void *addrs_ptr[ARRAY_COUNT(addrs)];

    numLevels = backtrace(addrs_ptr, ARRAY_COUNT(addrs));

    int offs = 0;
    // if we want to trim levels of the stack, we can do that here
    // by incrementing offs and decrementing numLevels
    while(numLevels > 0 && addrs_ptr[offs] >= renderdocBase && addrs_ptr[offs] < renderdocEnd)
    {
      offs++;
      numLevels--;
    }

    for(int i = 0; i < numLevels; i++)
      addrs[i] = (uint64_t)addrs_ptr[i + offs];
  }

  uint64_t addrs[128];
  int numLevels;
};

namespace Callstack
{
void Init()
{
  // look for our own line
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  if(f)
  {
    while(!feof(f))
    {
      char line[512] = {0};
      if(fgets(line, 511, f))
      {
        if(strstr(line, "librenderdoc") && strstr(line, "r-xp"))
        {
          sscanf(line, "%p-%p", &renderdocBase, &renderdocEnd);
          break;
        }
      }
    }

    FileIO::fclose(f);
  }
}

Stackwalk *Collect()
{
  return new LinuxCallstack();
}

Stackwalk *Create()
{
  return new LinuxCallstack(NULL, 0);
}

bool GetLoadedModules(byte *buf, size_t &size)
{
  // we just dump the whole file rather than pre-parsing, that way we can improve
  // parsing without needing to recapture
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  if(buf)
    memcpy(buf, "LNUXCALL", 8);

  size += 8;

  byte dummy[512];

  while(!feof(f))
  {
    byte *readbuf = buf ? buf + size : dummy;
    size += FileIO::fread(readbuf, 1, 512, f);
  }

  FileIO::fclose(f);

  return true;
}

struct LookupModule
{
  uint64_t base;
  uint64_t end;
  char path[2048];
};

class LinuxResolver : public Callstack::StackResolver
{
public:
  LinuxResolver(vector<LookupModule> modules) { m_Modules = modules; }
  Callstack::AddressDetails GetAddr(uint64_t addr)
  {
    EnsureCached(addr);

    return m_Cache[addr];
  }

private:
  void EnsureCached(uint64_t addr)
  {
    auto it = m_Cache.insert(
        std::pair<uint64_t, Callstack::AddressDetails>(addr, Callstack::AddressDetails()));
    if(!it.second)
      return;

    Callstack::AddressDetails &ret = it.first->second;

    ret.filename = "Unknown";
    ret.line = 0;
    ret.function = StringFormat::Fmt("0x%08llx", addr);

    for(size_t i = 0; i < m_Modules.size(); i++)
    {
      if(addr >= m_Modules[i].base && addr < m_Modules[i].end)
      {
        uint64_t relative = addr - m_Modules[i].base;
        string cmd =
            StringFormat::Fmt("addr2line -j.text -fCe \"%s\" 0x%llx", m_Modules[i].path, relative);

        FILE *f = ::popen(cmd.c_str(), "r");

        char result[2048] = {0};
        fread(result, 1, 2047, f);

        fclose(f);

        char *line2 = strchr(result, '\n');
        if(line2)
        {
          *line2 = 0;
          line2++;
        }

        ret.function = result;

        if(line2)
        {
          char *last = line2 + strlen(line2) - 1;
          uint32_t mul = 1;
          ret.line = 0;
          while(*last >= '0' && *last <= '9')
          {
            ret.line += mul * (uint32_t(*last) - uint32_t('0'));
            *last = 0;
            last--;
            mul *= 10;
          }
          if(*last == ':')
            *last = 0;

          ret.filename = line2;
        }

        break;
      }
    }
  }

  std::vector<LookupModule> m_Modules;
  std::map<uint64_t, Callstack::AddressDetails> m_Cache;
};

StackResolver *MakeResolver(byte *moduleDB, size_t DBSize, RENDERDOC_ProgressCallback progress)
{
  // we look in the original locations for the files, we don't prompt if we can't
  // find the file, or the file doesn't have symbols (and we don't validate that
  // the file is the right version). A good option for doing this would be
  // http://github.com/mlabbe/nativefiledialog

  if(DBSize < 8 || memcmp(moduleDB, "LNUXCALL", 8))
  {
    RDCWARN("Can't load callstack resolve for this log. Possibly from another platform?");
    return NULL;
  }

  char *start = (char *)(moduleDB + 8);
  char *search = start;
  char *dbend = (char *)(moduleDB + DBSize);

  vector<LookupModule> modules;

  while(search && search < dbend)
  {
    if(progress)
      progress(float(search - start) / float(DBSize));

    // find .text segments
    {
      long unsigned int base = 0, end = 0;

      int inode = 0;
      int offs = 0;
      //                        base-end   perms offset devid   inode offs
      int num = sscanf(search, "%lx-%lx  r-xp  %*x    %*x:%*x %d    %n", &base, &end, &inode, &offs);

      // we don't care about inode actually, we ust use it to verify that
      // we read all 3 params (and so perms == r-xp)
      if(num == 3 && offs > 0)
      {
        LookupModule mod = {0};

        mod.base = (uint64_t)base;
        mod.end = (uint64_t)end;

        search += offs;
        while(search < dbend && (*search == ' ' || *search == '\t'))
          search++;

        if(search < dbend && *search != '[' && *search != 0 && *search != '\n')
        {
          size_t n = ARRAY_COUNT(mod.path) - 1;
          mod.path[n] = 0;
          for(size_t i = 0; i < n; i++)
          {
            if(search[i] == 0 || search[i] == '\n')
            {
              mod.path[i] = 0;
              break;
            }
            if(search + i >= dbend)
            {
              mod.path[i] = 0;
              break;
            }
            mod.path[i] = search[i];
          }

          // addr2line wants offsets relative to text section, have to find offset of .text section
          // in this
          // mmapped section

          int textoffs = 0;
          string cmd = StringFormat::Fmt("readelf -WS \"%s\"", mod.path);

          FILE *f = ::popen(cmd.c_str(), "r");

          char result[4096] = {0};
          fread(result, 1, 4095, f);

          fclose(f);

          // find .text line
          char *find = strstr(result, ".text");

          if(find)
          {
            find += 5;

            while(isalpha(*find) || isspace(*find))
              find++;

            // virtual address is listed first, we want the offset
            sscanf(find, "%*x %x", &textoffs);

            mod.base += textoffs;

            modules.push_back(mod);
          }
        }
      }
    }

    if(progress)
      progress(RDCMIN(1.0f, float(search - start) / float(DBSize)));

    if(search >= dbend)
      break;

    search = strchr(search, '\n');
    if(search)
      search++;
  }

  return new LinuxResolver(modules);
}
};
<commit_msg>Fix handling of addr2line output in linux callstacks<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2018 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <execinfo.h>
#include <stdio.h>
#include <string.h>
#include <map>
#include <vector>
#include "os/os_specific.h"

void *renderdocBase = NULL;
void *renderdocEnd = NULL;

class LinuxCallstack : public Callstack::Stackwalk
{
public:
  LinuxCallstack()
  {
    RDCEraseEl(addrs);
    numLevels = 0;
    Collect();
  }
  LinuxCallstack(uint64_t *calls, size_t num) { Set(calls, num); }
  ~LinuxCallstack() {}
  void Set(uint64_t *calls, size_t num)
  {
    numLevels = num;
    for(int i = 0; i < numLevels; i++)
      addrs[i] = calls[i];
  }

  size_t NumLevels() const { return size_t(numLevels); }
  const uint64_t *GetAddrs() const { return addrs; }
private:
  LinuxCallstack(const Callstack::Stackwalk &other);

  void Collect()
  {
    void *addrs_ptr[ARRAY_COUNT(addrs)];

    numLevels = backtrace(addrs_ptr, ARRAY_COUNT(addrs));

    int offs = 0;
    // if we want to trim levels of the stack, we can do that here
    // by incrementing offs and decrementing numLevels
    while(numLevels > 0 && addrs_ptr[offs] >= renderdocBase && addrs_ptr[offs] < renderdocEnd)
    {
      offs++;
      numLevels--;
    }

    for(int i = 0; i < numLevels; i++)
      addrs[i] = (uint64_t)addrs_ptr[i + offs];
  }

  uint64_t addrs[128];
  int numLevels;
};

namespace Callstack
{
void Init()
{
  // look for our own line
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  if(f)
  {
    while(!feof(f))
    {
      char line[512] = {0};
      if(fgets(line, 511, f))
      {
        if(strstr(line, "librenderdoc") && strstr(line, "r-xp"))
        {
          sscanf(line, "%p-%p", &renderdocBase, &renderdocEnd);
          break;
        }
      }
    }

    FileIO::fclose(f);
  }
}

Stackwalk *Collect()
{
  return new LinuxCallstack();
}

Stackwalk *Create()
{
  return new LinuxCallstack(NULL, 0);
}

bool GetLoadedModules(byte *buf, size_t &size)
{
  // we just dump the whole file rather than pre-parsing, that way we can improve
  // parsing without needing to recapture
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  size = 0;

  if(buf)
    memcpy(buf, "LNUXCALL", 8);

  size += 8;

  byte dummy[512];

  while(!feof(f))
  {
    byte *readbuf = buf ? buf + size : dummy;
    size += FileIO::fread(readbuf, 1, 512, f);
  }

  FileIO::fclose(f);

  return true;
}

struct LookupModule
{
  uint64_t base;
  uint64_t end;
  char path[2048];
};

class LinuxResolver : public Callstack::StackResolver
{
public:
  LinuxResolver(vector<LookupModule> modules) { m_Modules = modules; }
  Callstack::AddressDetails GetAddr(uint64_t addr)
  {
    EnsureCached(addr);

    return m_Cache[addr];
  }

private:
  void EnsureCached(uint64_t addr)
  {
    auto it = m_Cache.insert(
        std::pair<uint64_t, Callstack::AddressDetails>(addr, Callstack::AddressDetails()));
    if(!it.second)
      return;

    Callstack::AddressDetails &ret = it.first->second;

    ret.filename = "Unknown";
    ret.line = 0;
    ret.function = StringFormat::Fmt("0x%08llx", addr);

    for(size_t i = 0; i < m_Modules.size(); i++)
    {
      if(addr >= m_Modules[i].base && addr < m_Modules[i].end)
      {
        uint64_t relative = addr - m_Modules[i].base;
        string cmd =
            StringFormat::Fmt("addr2line -j.text -fCe \"%s\" 0x%llx", m_Modules[i].path, relative);

        FILE *f = ::popen(cmd.c_str(), "r");

        char result[2048] = {0};
        fread(result, 1, 2047, f);

        fclose(f);

        char *line2 = strchr(result, '\n');
        if(line2)
        {
          *line2 = 0;
          line2++;
        }

        ret.function = result;

        if(line2)
        {
          char *linenum = line2 + strlen(line2) - 1;
          while(linenum > line2 && *linenum != ':')
            linenum--;

          ret.line = 0;

          if(*linenum == ':')
          {
            *linenum = 0;
            linenum++;

            while(*linenum >= '0' && *linenum <= '9')
            {
              ret.line *= 10;
              ret.line += (uint32_t(*linenum) - uint32_t('0'));
              linenum++;
            }
          }

          ret.filename = line2;
        }

        break;
      }
    }
  }

  std::vector<LookupModule> m_Modules;
  std::map<uint64_t, Callstack::AddressDetails> m_Cache;
};

StackResolver *MakeResolver(byte *moduleDB, size_t DBSize, RENDERDOC_ProgressCallback progress)
{
  // we look in the original locations for the files, we don't prompt if we can't
  // find the file, or the file doesn't have symbols (and we don't validate that
  // the file is the right version). A good option for doing this would be
  // http://github.com/mlabbe/nativefiledialog

  if(DBSize < 8 || memcmp(moduleDB, "LNUXCALL", 8))
  {
    RDCWARN("Can't load callstack resolve for this log. Possibly from another platform?");
    return NULL;
  }

  char *start = (char *)(moduleDB + 8);
  char *search = start;
  char *dbend = (char *)(moduleDB + DBSize);

  vector<LookupModule> modules;

  while(search && search < dbend)
  {
    if(progress)
      progress(float(search - start) / float(DBSize));

    // find .text segments
    {
      long unsigned int base = 0, end = 0;

      int inode = 0;
      int offs = 0;
      //                        base-end   perms offset devid   inode offs
      int num = sscanf(search, "%lx-%lx  r-xp  %*x    %*x:%*x %d    %n", &base, &end, &inode, &offs);

      // we don't care about inode actually, we ust use it to verify that
      // we read all 3 params (and so perms == r-xp)
      if(num == 3 && offs > 0)
      {
        LookupModule mod = {0};

        mod.base = (uint64_t)base;
        mod.end = (uint64_t)end;

        search += offs;
        while(search < dbend && (*search == ' ' || *search == '\t'))
          search++;

        if(search < dbend && *search != '[' && *search != 0 && *search != '\n')
        {
          size_t n = ARRAY_COUNT(mod.path) - 1;
          mod.path[n] = 0;
          for(size_t i = 0; i < n; i++)
          {
            if(search[i] == 0 || search[i] == '\n')
            {
              mod.path[i] = 0;
              break;
            }
            if(search + i >= dbend)
            {
              mod.path[i] = 0;
              break;
            }
            mod.path[i] = search[i];
          }

          // addr2line wants offsets relative to text section, have to find offset of .text section
          // in this
          // mmapped section

          int textoffs = 0;
          string cmd = StringFormat::Fmt("readelf -WS \"%s\"", mod.path);

          FILE *f = ::popen(cmd.c_str(), "r");

          char result[4096] = {0};
          fread(result, 1, 4095, f);

          fclose(f);

          // find .text line
          char *find = strstr(result, ".text");

          if(find)
          {
            find += 5;

            while(isalpha(*find) || isspace(*find))
              find++;

            // virtual address is listed first, we want the offset
            sscanf(find, "%*x %x", &textoffs);

            mod.base += textoffs;

            modules.push_back(mod);
          }
        }
      }
    }

    if(progress)
      progress(RDCMIN(1.0f, float(search - start) / float(DBSize)));

    if(search >= dbend)
      break;

    search = strchr(search, '\n');
    if(search)
      search++;
  }

  return new LinuxResolver(modules);
}
};
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2020 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <execinfo.h>
#include <stdio.h>
#include <string.h>
#include <map>
#include "common/common.h"
#include "common/formatting.h"
#include "os/os_specific.h"

void *renderdocBase = NULL;
void *renderdocEnd = NULL;

class LinuxCallstack : public Callstack::Stackwalk
{
public:
  LinuxCallstack()
  {
    RDCEraseEl(addrs);
    numLevels = 0;
    Collect();
  }
  LinuxCallstack(uint64_t *calls, size_t num) { Set(calls, num); }
  ~LinuxCallstack() {}
  void Set(uint64_t *calls, size_t num)
  {
    numLevels = num;
    for(size_t i = 0; i < numLevels; i++)
      addrs[i] = calls[i];
  }

  size_t NumLevels() const { return numLevels; }
  const uint64_t *GetAddrs() const { return addrs; }
private:
  LinuxCallstack(const Callstack::Stackwalk &other);

  void Collect()
  {
    void *addrs_ptr[ARRAY_COUNT(addrs)];

    int ret = backtrace(addrs_ptr, ARRAY_COUNT(addrs));

    numLevels = 0;
    if(ret > 0)
      numLevels = (size_t)ret;

    int offs = 0;
    // if we want to trim levels of the stack, we can do that here
    // by incrementing offs and decrementing numLevels
    while(numLevels > 0 && addrs_ptr[offs] >= renderdocBase && addrs_ptr[offs] < renderdocEnd)
    {
      offs++;
      numLevels--;
    }

    for(size_t i = 0; i < numLevels; i++)
      addrs[i] = (uint64_t)addrs_ptr[i + offs];
  }

  uint64_t addrs[128];
  size_t numLevels;
};

namespace Callstack
{
void Init()
{
  // look for our own line
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  if(f)
  {
    while(!feof(f))
    {
      char line[512] = {0};
      if(fgets(line, 511, f))
      {
        if(strstr(line, "librenderdoc") && strstr(line, "r-xp"))
        {
          sscanf(line, "%p-%p", &renderdocBase, &renderdocEnd);
          break;
        }
      }
    }

    FileIO::fclose(f);
  }
}

Stackwalk *Collect()
{
  return new LinuxCallstack();
}

Stackwalk *Create()
{
  return new LinuxCallstack(NULL, 0);
}

bool GetLoadedModules(byte *buf, size_t &size)
{
  // we just dump the whole file rather than pre-parsing, that way we can improve
  // parsing without needing to recapture
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  size = 0;

  if(buf)
    memcpy(buf, "LNUXCALL", 8);

  size += 8;

  byte dummy[512];

  while(!feof(f))
  {
    byte *readbuf = buf ? buf + size : dummy;
    size += FileIO::fread(readbuf, 1, 512, f);
  }

  FileIO::fclose(f);

  return true;
}

struct LookupModule
{
  uint64_t base;
  uint64_t end;
  uint64_t offset;
  char path[2048];
};

class LinuxResolver : public Callstack::StackResolver
{
public:
  LinuxResolver(rdcarray<LookupModule> modules) { m_Modules = modules; }
  Callstack::AddressDetails GetAddr(uint64_t addr)
  {
    EnsureCached(addr);

    return m_Cache[addr];
  }

private:
  void EnsureCached(uint64_t addr)
  {
    auto it = m_Cache.insert(
        std::pair<uint64_t, Callstack::AddressDetails>(addr, Callstack::AddressDetails()));
    if(!it.second)
      return;

    Callstack::AddressDetails &ret = it.first->second;

    ret.filename = "Unknown";
    ret.line = 0;
    ret.function = StringFormat::Fmt("0x%08llx", addr);

    for(size_t i = 0; i < m_Modules.size(); i++)
    {
      if(addr >= m_Modules[i].base && addr < m_Modules[i].end)
      {
        uint64_t relative = addr - m_Modules[i].base + m_Modules[i].offset;
        rdcstr cmd = StringFormat::Fmt("addr2line -fCe \"%s\" 0x%llx", m_Modules[i].path, relative);

        FILE *f = ::popen(cmd.c_str(), "r");

        char result[2048] = {0};
        fread(result, 1, 2047, f);

        fclose(f);

        char *line2 = strchr(result, '\n');
        if(line2)
        {
          *line2 = 0;
          line2++;
        }

        ret.function = result;

        if(line2)
        {
          char *linenum = line2 + strlen(line2) - 1;
          while(linenum > line2 && *linenum != ':')
            linenum--;

          ret.line = 0;

          if(*linenum == ':')
          {
            *linenum = 0;
            linenum++;

            while(*linenum >= '0' && *linenum <= '9')
            {
              ret.line *= 10;
              ret.line += (uint32_t(*linenum) - uint32_t('0'));
              linenum++;
            }
          }

          ret.filename = line2;
        }

        break;
      }
    }
  }

  rdcarray<LookupModule> m_Modules;
  std::map<uint64_t, Callstack::AddressDetails> m_Cache;
};

StackResolver *MakeResolver(bool interactive, byte *moduleDB, size_t DBSize,
                            RENDERDOC_ProgressCallback progress)
{
  // we look in the original locations for the files, we don't prompt if we can't
  // find the file, or the file doesn't have symbols (and we don't validate that
  // the file is the right version). A good option for doing this would be
  // http://github.com/mlabbe/nativefiledialog

  if(DBSize < 8 || memcmp(moduleDB, "LNUXCALL", 8))
  {
    RDCWARN("Can't load callstack resolve for this log. Possibly from another platform?");
    return NULL;
  }

  char *start = (char *)(moduleDB + 8);
  char *search = start;
  char *dbend = (char *)(moduleDB + DBSize);

  rdcarray<LookupModule> modules;

  while(search && search < dbend)
  {
    if(progress)
      progress(float(search - start) / float(DBSize));

    // find .text segments
    {
      long unsigned int base = 0, end = 0, offset = 0;

      int inode = 0;
      int offs = 0;
      //                        base-end   perms offset devid   inode offs
      int num = sscanf(search, "%lx-%lx  r-xp  %lx    %*x:%*x %d    %n", &base, &end, &offset,
                       &inode, &offs);

      // we don't care about inode actually, we ust use it to verify that
      // we read all 4 params (and so perms == r-xp)
      if(num == 4 && offs > 0)
      {
        LookupModule mod = {0};

        mod.base = (uint64_t)base;
        mod.end = (uint64_t)end;
        mod.offset = (uint64_t)offset;

        search += offs;
        while(search < dbend && (*search == ' ' || *search == '\t'))
          search++;

        if(search < dbend && *search != '[' && *search != 0 && *search != '\n')
        {
          size_t n = ARRAY_COUNT(mod.path) - 1;
          mod.path[n] = 0;
          for(size_t i = 0; i < n; i++)
          {
            if(search[i] == 0 || search[i] == '\n')
            {
              mod.path[i] = 0;
              break;
            }
            if(search + i >= dbend)
            {
              mod.path[i] = 0;
              break;
            }
            mod.path[i] = search[i];
          }

          modules.push_back(mod);
        }
      }
    }

    if(progress)
      progress(RDCMIN(1.0f, float(search - start) / float(DBSize)));

    if(search >= dbend)
      break;

    search = strchr(search, '\n');
    if(search)
      search++;
  }

  return new LinuxResolver(modules);
}
};
<commit_msg>Use dl_iterate_phdr to generate non-PIE compatible mapping. Closes #1773<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2020 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

// for dl_iterate_phdr
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <execinfo.h>
#include <link.h>
#include <stdio.h>
#include <string.h>
#include <map>
#include "common/common.h"
#include "common/formatting.h"
#include "os/os_specific.h"

void *renderdocBase = NULL;
void *renderdocEnd = NULL;

class LinuxCallstack : public Callstack::Stackwalk
{
public:
  LinuxCallstack()
  {
    RDCEraseEl(addrs);
    numLevels = 0;
    Collect();
  }
  LinuxCallstack(uint64_t *calls, size_t num) { Set(calls, num); }
  ~LinuxCallstack() {}
  void Set(uint64_t *calls, size_t num)
  {
    numLevels = num;
    for(size_t i = 0; i < numLevels; i++)
      addrs[i] = calls[i];
  }

  size_t NumLevels() const { return numLevels; }
  const uint64_t *GetAddrs() const { return addrs; }
private:
  LinuxCallstack(const Callstack::Stackwalk &other);

  void Collect()
  {
    void *addrs_ptr[ARRAY_COUNT(addrs)];

    int ret = backtrace(addrs_ptr, ARRAY_COUNT(addrs));

    numLevels = 0;
    if(ret > 0)
      numLevels = (size_t)ret;

    int offs = 0;
    // if we want to trim levels of the stack, we can do that here
    // by incrementing offs and decrementing numLevels
    while(numLevels > 0 && addrs_ptr[offs] >= renderdocBase && addrs_ptr[offs] < renderdocEnd)
    {
      offs++;
      numLevels--;
    }

    for(size_t i = 0; i < numLevels; i++)
      addrs[i] = (uint64_t)addrs_ptr[i + offs];
  }

  uint64_t addrs[128];
  size_t numLevels;
};

namespace Callstack
{
void Init()
{
  // look for our own line
  FILE *f = FileIO::fopen("/proc/self/maps", "r");

  if(f)
  {
    while(!feof(f))
    {
      char line[512] = {0};
      if(fgets(line, 511, f))
      {
        if(strstr(line, "librenderdoc") && strstr(line, "r-xp"))
        {
          sscanf(line, "%p-%p", &renderdocBase, &renderdocEnd);
          break;
        }
      }
    }

    FileIO::fclose(f);
  }
}

Stackwalk *Collect()
{
  return new LinuxCallstack();
}

Stackwalk *Create()
{
  return new LinuxCallstack(NULL, 0);
}

static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *data)
{
  if(info->dlpi_name == NULL)
  {
    RDCLOG("Skipping NULL entry!");
    return 0;
  }

  rdcstr *out = (rdcstr *)data;

  rdcstr name = info->dlpi_name;
  if(name.empty())
    FileIO::GetExecutableFilename(name);

  name = FileIO::GetFullPathname(name);

  for(int j = 0; j < info->dlpi_phnum; j++)
  {
    uint32_t rxMask = PF_R | PF_X;
    if(info->dlpi_phdr[j].p_type == PT_LOAD && (info->dlpi_phdr[j].p_flags & rxMask) == rxMask)
    {
      uint64_t baseAddr = info->dlpi_addr + info->dlpi_phdr[j].p_vaddr;
      *out += StringFormat::Fmt("%llx-%llx r-xp %08x 123:45 12345678    %s\n", baseAddr,
                                baseAddr + info->dlpi_phdr[j].p_memsz, info->dlpi_phdr[j].p_vaddr,
                                name.c_str());
    }
  }

  return 0;
}

bool GetLoadedModules(byte *buf, size_t &size)
{
  size = 0;

  if(buf)
  {
    memcpy(buf, "LNUXCALL", 8);
    buf += 8;
  }

  size += 8;

  // generate a fake /proc/self/maps. This is mostly for backwards compatibility, we could generate
  // a more compact representation. The slight difference is that we change how we calculate the
  // offset for each segment, so that we handle non-PIE executables properly.
  rdcstr fake_maps;

  dl_iterate_phdr(dl_iterate_callback, &fake_maps);

  size += fake_maps.size();

  if(buf)
    memcpy(buf, fake_maps.data(), fake_maps.size());

  return true;
}

struct LookupModule
{
  uint64_t base;
  uint64_t end;
  uint64_t offset;
  char path[2048];
};

class LinuxResolver : public Callstack::StackResolver
{
public:
  LinuxResolver(rdcarray<LookupModule> modules) { m_Modules = modules; }
  Callstack::AddressDetails GetAddr(uint64_t addr)
  {
    EnsureCached(addr);

    return m_Cache[addr];
  }

private:
  void EnsureCached(uint64_t addr)
  {
    auto it = m_Cache.insert(
        std::pair<uint64_t, Callstack::AddressDetails>(addr, Callstack::AddressDetails()));
    if(!it.second)
      return;

    Callstack::AddressDetails &ret = it.first->second;

    ret.filename = "Unknown";
    ret.line = 0;
    ret.function = StringFormat::Fmt("0x%08llx", addr);

    for(size_t i = 0; i < m_Modules.size(); i++)
    {
      if(addr >= m_Modules[i].base && addr < m_Modules[i].end)
      {
        RDCLOG("%llx relative to module %llx-%llx, with offset %llx", addr, m_Modules[i].base,
               m_Modules[i].end, m_Modules[i].offset);
        uint64_t relative = addr - m_Modules[i].base + m_Modules[i].offset;
        rdcstr cmd = StringFormat::Fmt("addr2line -fCe \"%s\" 0x%llx", m_Modules[i].path, relative);

        RDCLOG(": %s", cmd.c_str());

        FILE *f = ::popen(cmd.c_str(), "r");

        char result[2048] = {0};
        fread(result, 1, 2047, f);

        fclose(f);

        char *line2 = strchr(result, '\n');
        if(line2)
        {
          *line2 = 0;
          line2++;
        }

        ret.function = result;

        if(line2)
        {
          char *linenum = line2 + strlen(line2) - 1;
          while(linenum > line2 && *linenum != ':')
            linenum--;

          ret.line = 0;

          if(*linenum == ':')
          {
            *linenum = 0;
            linenum++;

            while(*linenum >= '0' && *linenum <= '9')
            {
              ret.line *= 10;
              ret.line += (uint32_t(*linenum) - uint32_t('0'));
              linenum++;
            }
          }

          ret.filename = line2;
        }

        break;
      }
    }
  }

  rdcarray<LookupModule> m_Modules;
  std::map<uint64_t, Callstack::AddressDetails> m_Cache;
};

StackResolver *MakeResolver(bool interactive, byte *moduleDB, size_t DBSize,
                            RENDERDOC_ProgressCallback progress)
{
  // we look in the original locations for the files, we don't prompt if we can't
  // find the file, or the file doesn't have symbols (and we don't validate that
  // the file is the right version). A good option for doing this would be
  // http://github.com/mlabbe/nativefiledialog

  if(DBSize < 8 || memcmp(moduleDB, "LNUXCALL", 8))
  {
    RDCWARN("Can't load callstack resolve for this log. Possibly from another platform?");
    return NULL;
  }

  char *start = (char *)(moduleDB + 8);
  char *search = start;
  char *dbend = (char *)(moduleDB + DBSize);

  rdcarray<LookupModule> modules;

  while(search && search < dbend)
  {
    if(progress)
      progress(float(search - start) / float(DBSize));

    // find .text segments
    {
      long unsigned int base = 0, end = 0, offset = 0;

      int inode = 0;
      int offs = 0;
      //                        base-end   perms offset devid   inode offs
      int num = sscanf(search, "%lx-%lx  r-xp  %lx    %*x:%*x %d    %n", &base, &end, &offset,
                       &inode, &offs);

      // we don't care about inode actually, we ust use it to verify that
      // we read all 4 params (and so perms == r-xp)
      if(num == 4 && offs > 0)
      {
        LookupModule mod = {0};

        mod.base = (uint64_t)base;
        mod.end = (uint64_t)end;
        mod.offset = (uint64_t)offset;

        search += offs;
        while(search < dbend && (*search == ' ' || *search == '\t'))
          search++;

        if(search < dbend && *search != '[' && *search != 0 && *search != '\n')
        {
          size_t n = ARRAY_COUNT(mod.path) - 1;
          mod.path[n] = 0;
          for(size_t i = 0; i < n; i++)
          {
            if(search[i] == 0 || search[i] == '\n')
            {
              mod.path[i] = 0;
              break;
            }
            if(search + i >= dbend)
            {
              mod.path[i] = 0;
              break;
            }
            mod.path[i] = search[i];
          }

          modules.push_back(mod);
        }
      }
    }

    if(progress)
      progress(RDCMIN(1.0f, float(search - start) / float(DBSize)));

    if(search >= dbend)
      break;

    search = strchr(search, '\n');
    if(search)
      search++;
  }

  return new LinuxResolver(modules);
}
};
<|endoftext|>


<commit_before>#ifndef MDSYSEX_H__
#define MDSYSEX_H__

#include "WProgram.h"
#include "Midi.h"
#include "MidiSysex.hh"
#include "Vector.hh"
#include "Callback.hh"
#include "MD.h"

typedef enum {
    MD_NONE,

    MD_GET_CURRENT_KIT,
    MD_GET_KIT,

    MD_GET_CURRENT_GLOBAL,
    MD_GET_GLOBAL,

    MD_DONE
} getCurrentKitStatus_t;

class MDSysexListenerClass : public MidiSysexListenerClass {
public:
  CallbackVector<MDCallback,4> onGlobalMessageCallbacks;
  CallbackVector<MDCallback,4> onKitMessageCallbacks;
  CallbackVector<MDCallback,4> onSongMessageCallbacks;
  CallbackVector<MDCallback,4> onPatternMessageCallbacks;
  CallbackVector2<MDCallback,4,uint8_t,uint8_t> onStatusResponseCallbacks;

  bool isMDMessage;
  uint8_t msgType;

  MDSysexListenerClass() : MidiSysexListenerClass() {
    ids[0] = 0;
    ids[1] = 0x20;
    ids[2] = 0x3c;
  }

  void addOnStatusResponseCallback(MDCallback *obj, md_status_callback_ptr_t func) {
    onStatusResponseCallbacks.add(obj, func);
  }
  void removeOnStatusResponseCallback(MDCallback *obj, md_status_callback_ptr_t func) {
    onStatusResponseCallbacks.remove(obj, func);
  }
  void removeOnStatusResponseCallback(MDCallback *obj) {
    onStatusResponseCallbacks.remove(obj);
  }

  void addOnGlobalMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onGlobalMessageCallbacks.add(obj, func);
  }
  void removeOnGlobalMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onGlobalMessageCallbacks.remove(obj, func);
  }
  void removeOnGlobalMessageCallback(MDCallback *obj) {
    onGlobalMessageCallbacks.remove(obj);
  }

  void addOnKitMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onKitMessageCallbacks.add(obj, func);
  }
  void removeOnKitMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onKitMessageCallbacks.remove(obj, func);
  }
  void removeOnKitMessageCallback(MDCallback *obj) {
    onKitMessageCallbacks.remove(obj);
  }

  void addOnPatternMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onPatternMessageCallbacks.add(obj, func);
  }
  void removeOnPatternMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onPatternMessageCallbacks.remove(obj, func);
  }
  void removeOnPatternMessageCallback(MDCallback *obj) {
    onPatternMessageCallbacks.remove(obj);
  }

  void addOnSongMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onSongMessageCallbacks.add(obj, func);
  }
  void removeOnSongMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onSongMessageCallbacks.remove(obj, func);
  }
  void removeOnSongMessageCallback(MDCallback *obj) {
    onSongMessageCallbacks.remove(obj);
  }

  virtual void start();
  virtual void handleByte(uint8_t byte);
  virtual void end();

  void setup();
};

#include "MDMessages.hh"

extern MDSysexListenerClass MDSysexListener;

#endif /* MDSYSEX_H__ */
<commit_msg>cosmetics<commit_after>#ifndef MDSYSEX_H__
#define MDSYSEX_H__

#include "WProgram.h"
#include "Midi.h"
#include "MidiSysex.hh"
#include "Vector.hh"
#include "Callback.hh"
#include "MD.h"

typedef enum {
    MD_NONE,

    MD_GET_CURRENT_KIT,
    MD_GET_KIT,

    MD_GET_CURRENT_GLOBAL,
    MD_GET_GLOBAL,

    MD_DONE
} getCurrentKitStatus_t;

class MDSysexListenerClass : public MidiSysexListenerClass {
public:
  CallbackVector<MDCallback,4> onGlobalMessageCallbacks;
  CallbackVector<MDCallback,4> onKitMessageCallbacks;
  CallbackVector<MDCallback,4> onSongMessageCallbacks;
  CallbackVector<MDCallback,4> onPatternMessageCallbacks;
  CallbackVector2<MDCallback,4,uint8_t,uint8_t> onStatusResponseCallbacks;

  bool isMDMessage;
  uint8_t msgType;

  MDSysexListenerClass() : MidiSysexListenerClass() {
    ids[0] = 0;
    ids[1] = 0x20;
    ids[2] = 0x3c;
  }

  virtual void start();
  virtual void handleByte(uint8_t byte);
  virtual void end();

  void setup();

  void addOnStatusResponseCallback(MDCallback *obj, md_status_callback_ptr_t func) {
    onStatusResponseCallbacks.add(obj, func);
  }
  void removeOnStatusResponseCallback(MDCallback *obj, md_status_callback_ptr_t func) {
    onStatusResponseCallbacks.remove(obj, func);
  }
  void removeOnStatusResponseCallback(MDCallback *obj) {
    onStatusResponseCallbacks.remove(obj);
  }

  void addOnGlobalMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onGlobalMessageCallbacks.add(obj, func);
  }
  void removeOnGlobalMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onGlobalMessageCallbacks.remove(obj, func);
  }
  void removeOnGlobalMessageCallback(MDCallback *obj) {
    onGlobalMessageCallbacks.remove(obj);
  }

  void addOnKitMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onKitMessageCallbacks.add(obj, func);
  }
  void removeOnKitMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onKitMessageCallbacks.remove(obj, func);
  }
  void removeOnKitMessageCallback(MDCallback *obj) {
    onKitMessageCallbacks.remove(obj);
  }

  void addOnPatternMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onPatternMessageCallbacks.add(obj, func);
  }
  void removeOnPatternMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onPatternMessageCallbacks.remove(obj, func);
  }
  void removeOnPatternMessageCallback(MDCallback *obj) {
    onPatternMessageCallbacks.remove(obj);
  }

  void addOnSongMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onSongMessageCallbacks.add(obj, func);
  }
  void removeOnSongMessageCallback(MDCallback *obj, md_callback_ptr_t func) {
    onSongMessageCallbacks.remove(obj, func);
  }
  void removeOnSongMessageCallback(MDCallback *obj) {
    onSongMessageCallbacks.remove(obj);
  }

};

#include "MDMessages.hh"

extern MDSysexListenerClass MDSysexListener;

#endif /* MDSYSEX_H__ */
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbImage.h"
#include "itkPointSet.h"
#include "otbLineSpatialObjectListToRightAnglePointSetFilter.h"
#include "otbLineSpatialObjectList.h"
#include "otbDrawLineSpatialObjectListFilter.h"
#include "otbLineSegmentDetector.h"

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include <iostream>
#include <fstream>

int main( int argc, char * argv[] )
{
  const   char * infname   = argv[1];
  const   char * outfname  = argv[2];

  const unsigned int           Dimension = 2;
  typedef float                PixelType;

  /** Typedefs */
  typedef otb::Image<PixelType ,Dimension>   ImageType;
  typedef otb::ImageFileReader<ImageType>    ReaderType;
  typedef otb::ImageFileWriter<ImageType>    WriterType;
  typedef otb::LineSpatialObjectList         LinesListType;
  typedef LinesListType::LineType            LineType;
  typedef std::vector<LineType*>             VectorLines;
  typedef itk::PointSet<VectorLines , Dimension>     PointSetType;
  typedef otb::LineSegmentDetector<ImageType , PixelType>   lsdFilterType;
  typedef otb::LineSpatialObjectListToRightAnglePointSetFilter<ImageType,
                                            LinesListType, PointSetType>
                                                    RightAngleFilterType;

  /** Creatop, of an instance of the filters */
  RightAngleFilterType::Pointer  rightAngleFilter  =
                                               RightAngleFilterType::New();
  ReaderType::Pointer            reader            = ReaderType::New();
  PointSetType::Pointer          segmentOrtho      = PointSetType::New();
  lsdFilterType::Pointer         lsdFilter         = lsdFilterType::New();

  // Begin the process
  reader->SetFileName(infname);
  lsdFilter->SetInput(reader->GetOutput());

  rightAngleFilter->SetInputImage(reader->GetOutput());
  rightAngleFilter->SetInput(lsdFilter->GetOutput());
  rightAngleFilter->Update();

  /** Print the right angles coordinate in the output file*/
  segmentOrtho = rightAngleFilter->GetOutput();
  PointSetType::PointType   pRight;
  VectorLines               outputVectorLines;
  LinesListType::Pointer    outputLinesList = LinesListType::New();

  std::ofstream outfile(outfname);
  for (unsigned int i = 0; i<segmentOrtho->GetNumberOfPoints() ; i++)
    {
      segmentOrtho->GetPoint(i, &pRight);
      outfile << " Right Angle found in point : " <<  pRight << std::endl;

      /** Exemple To extract The coordinate of the segment (Just for example)*/
      segmentOrtho->GetPointData(i, &outputVectorLines);
      outputLinesList->push_back(outputVectorLines[0]);
      outputLinesList->push_back(outputVectorLines[1]);
    }
  outfile.close();

  return EXIT_SUCCESS;
}

<commit_msg>DOC: RightAngleDetectionExample line drawing<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "otbImage.h"
#include "itkPointSet.h"
#include "otbLineSpatialObjectListToRightAnglePointSetFilter.h"
#include "otbLineSpatialObjectList.h"
#include "otbDrawLineSpatialObjectListFilter.h"
#include "otbLineSegmentDetector.h"

#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include <iostream>
#include <fstream>

int main( int argc, char * argv[] )
{
  const   char * infname   = argv[1];
  const   char * outfname  = argv[2];

  const unsigned int           Dimension = 2;
  typedef float                PixelType;

  /** Typedefs */
  typedef otb::Image<PixelType ,Dimension>   ImageType;
  typedef otb::ImageFileReader<ImageType>    ReaderType;
  typedef otb::ImageFileWriter<ImageType>    WriterType;
  typedef otb::LineSpatialObjectList         LinesListType;
  typedef LinesListType::LineType            LineType;
  typedef std::vector<LineType*>             VectorLines;
  typedef itk::PointSet<VectorLines , Dimension>     PointSetType;
  typedef otb::LineSegmentDetector<ImageType , PixelType>   lsdFilterType;
  typedef otb::LineSpatialObjectListToRightAnglePointSetFilter<ImageType,
                                            LinesListType, PointSetType>
                                                    RightAngleFilterType;

  /** Creatop, of an instance of the filters */
  RightAngleFilterType::Pointer  rightAngleFilter  =
                                               RightAngleFilterType::New();
  ReaderType::Pointer            reader            = ReaderType::New();
  PointSetType::Pointer          segmentOrtho      = PointSetType::New();
  lsdFilterType::Pointer         lsdFilter         = lsdFilterType::New();

  // Begin the process
  reader->SetFileName(infname);
  lsdFilter->SetInput(reader->GetOutput());

  rightAngleFilter->SetInputImage(reader->GetOutput());
  rightAngleFilter->SetInput(lsdFilter->GetOutput());
  rightAngleFilter->Update();

  /** Print the right angles coordinate in the output file*/
  segmentOrtho = rightAngleFilter->GetOutput();
  PointSetType::PointType   pRight;
  VectorLines               outputVectorLines;
  LinesListType::Pointer    outputLinesList = LinesListType::New();

  for (unsigned int i = 0; i<segmentOrtho->GetNumberOfPoints() ; i++)
    {
      segmentOrtho->GetPoint(i, &pRight);
      segmentOrtho->GetPointData(i, &outputVectorLines);
      outputLinesList->push_back(outputVectorLines[0]);
      outputLinesList->push_back(outputVectorLines[1]);
    }

  typedef otb::DrawLineSpatialObjectListFilter< ImageType,
                                       ImageType > DrawLineListType;
  DrawLineListType::Pointer drawLineFilter =   DrawLineListType::New();

    drawLineFilter->SetInput(reader->GetOutput());
  drawLineFilter->SetInputLineSpatialObjectList(outputLinesList);

  WriterType::Pointer writer = WriterType::New();
    writer->SetInput(drawLineFilter->GetOutput());
    writer->SetFileName(outfname);

  reader->GenerateOutputInformation();
  writer->Update();

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_Iterable_inl_
#define _Stroika_Foundation_Traversal_Iterable_inl_

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

            /*
             ********************************************************************************
             *************************** Iterable<T>::_IRep *********************************
             ********************************************************************************
             */
            template    <typename T>
            inline  bool    Iterable<T>::_IRep::_IsEmpty () const
            {
                return GetLength () == 0;
            }
            template    <typename T>
            inline  void    Iterable<T>::_IRep::_Apply (_APPLY_ARGTYPE doToElement) const
            {
                RequireNotNull (doToElement);
                for (Iterator<T> i = MakeIterator (this); i != Iterable<T>::end (); ++i) {
                    (doToElement) (*i);
                }
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::_IRep::_FindFirstThat (_APPLYUNTIL_ARGTYPE doToElement, IteratorOwnerID suggestedOwner) const
            {
                RequireNotNull (doToElement);
                for (Iterator<T> i = MakeIterator (suggestedOwner); i != Iterable<T>::end (); ++i) {
                    if ((doToElement) (*i)) {
                        return i;
                    }
                }
                return end ();
            }

            /*
             ********************************************************************************
             ********************************** Iterable<T> *********************************
             ********************************************************************************
             */
            template    <typename T>
            inline  Iterable<T>::Iterable (const _SharedPtrIRep& rep) noexcept
:
            fRep_ (rep)
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
            }
            template    <typename T>
            inline  Iterable<T>::Iterable (const Iterable<T>& from) noexcept
:
            fRep_ (from.fRep_)
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
            }
            template    <typename T>
            inline  Iterable<T>::Iterable (Iterable<T>&& from) noexcept
:
            fRep_ (std::move (from.fRep_))
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
            }
            template    <typename T>
            inline  Iterable<T>::Iterable (_SharedPtrIRep&& rep) noexcept
:
            fRep_ (std::move (rep))
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
            }
            template    <typename T>
            inline  Iterable<T>::~Iterable ()
            {
            }
            template    <typename T>
            inline  Iterable<T>&    Iterable<T>::operator= (const Iterable<T>& rhs)
            {
                RequireNotNull (rhs.fRep_.get ());
                fRep_ = rhs.fRep_;
                return *this;
            }
            template    <typename T>
            inline  typename Iterable<T>::_SharedPtrIRep  Iterable<T>::Clone_ (const _IRep& rep, IteratorOwnerID forIterableEnvelope)
            {
                return rep.Clone (forIterableEnvelope);
            }
            template    <typename T>
            inline  Memory::SharedByValue_State     Iterable<T>::_GetSharingState () const
            {
                return fRep_.GetSharingState ();
            }
            template    <typename T>
            inline  typename Iterable<T>::_IRep&         Iterable<T>::_GetRep ()
            {
                //EnsureNotNull (fRep_.get ());
                // subtle - but we must use the get () overload that allows passing in our Copy forward parameters
                // instead of using operator* (which doesnt allow passsing in the copy forward paramters).
                //
                // Note - our copy forward paramters are the container envelope pointer
                return *(fRep_.get (this));
            }
            template    <typename T>
            inline  const typename Iterable<T>::_IRep&   Iterable<T>::_GetRep () const
            {
                EnsureNotNull (fRep_.get ());
                return *fRep_;
            }
            template    <typename T>
            inline  const typename Iterable<T>::_IRep&   Iterable<T>::_ConstGetRep () const
            {
                EnsureNotNull (fRep_.get ());
                return *fRep_;
            }
            template    <typename T>
            inline  Iterator<T>     Iterable<T>::MakeIterator () const
            {
                return _GetRep ().MakeIterator (this);
            }
            template    <typename T>
            inline  size_t  Iterable<T>::GetLength () const
            {
                return _GetRep ().GetLength ();
            }
            template    <typename T>
            inline  bool    Iterable<T>::IsEmpty () const
            {
                return _GetRep ().IsEmpty ();
            }
            template    <typename T>
            template    <typename EQUALS_COMPARER>
            bool    Iterable<T>::Contains (const T& element) const
            {
                for (T i : *this) {
                    if (EQUALS_COMPARER::Equals (i, element)) {
                        return true;
                    }
                }
                return false;
            }
            template    <typename T>
            template    <typename RHS_CONTAINER_TYPE, typename EQUALS_COMPARER>
            bool    Iterable<T>::SetEquals (const RHS_CONTAINER_TYPE& rhs) const
            {
                /*
                 *  An extremely in-efficient but space-constant implementation. N^2 and check
                 *  a contains b and b contains a
                 */
                for (auto ti : *this) {
                    bool contained  =   false;
                    for (auto ri : rhs) {
                        if (EQUALS_COMPARER::Equals (ti, ri)) {
                            contained = true;
                            break;
                        }
                    }
                    if (not contained) {
                        return false;
                    }
                }
                for (auto ri : rhs) {
                    bool contained  =   false;
                    for (auto ti : *this) {
                        if (EQUALS_COMPARER::Equals (ti, ri)) {
                            contained = true;
                            break;
                        }
                    }
                    if (not contained) {
                        return false;
                    }
                }
                return true;
            }
            template    <typename T>
            template    <typename RHS_CONTAINER_TYPE, typename EQUALS_COMPARER>
            bool    Iterable<T>::MultiSetEquals (const RHS_CONTAINER_TYPE& rhs) const
            {
                auto    tallyOf = [] (const Iterable<T>& c, T item) -> size_t {
                    size_t  total = 0;
                    for (auto ti : c)
                    {
                        if (EQUALS_COMPARER::Equals (ti, item)) {
                            total++;
                        }
                    }
                    return total;
                };
                /*
                 *  An extremely in-efficient but space-constant implementation. N^3 and check
                 *  a contains b and b contains a
                 */
                for (auto ti : *this) {
                    if (tallyOf (*this, ti) != tallyOf (rhs, ti)) {
                        return false;
                    }
                }
                for (auto ti : rhs) {
                    if (tallyOf (*this, ti) != tallyOf (rhs, ti)) {
                        return false;
                    }
                }
                return true;
            }
            template    <typename T>
            template    <typename RHS_CONTAINER_TYPE, typename EQUALS_COMPARER>
            bool    Iterable<T>::ExactEquals (const RHS_CONTAINER_TYPE& rhs) const
            {
                Iterator<T> li  =   MakeIterator ();
                Iterator<T> le  =   end ();
                auto        ri  =   rhs.begin ();
                auto        re  =   rhs.end ();
                for (; li != le and ri != re; ++ri, ++li) {
                    if (not EQUALS_COMPARER::Equals (*li, *ri)) {
                        return false;
                    }
                }
                // only true if we get to end at the same time
                return li == le and ri == re;
            }
            template    <typename T>
            inline  bool    Iterable<T>::empty () const
            {
                return IsEmpty ();
            }
            template    <typename T>
            inline  size_t  Iterable<T>::length () const
            {
                return GetLength ();
            }
            template    <typename T>
            inline  size_t  Iterable<T>::size () const
            {
                return GetLength ();
            }
            template    <typename T>
            inline  Iterator<T> Iterable<T>::begin () const
            {
                return MakeIterator ();
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::end ()
            {
                return (Iterator<T>::GetEmptyIterator ());
            }
            template    <typename T>
            inline  void    Iterable<T>::ApplyStatic (void (*doToElement) (const T& item)) const
            {
                RequireNotNull (doToElement);
                _GetRep ().Apply (doToElement);
            }
            template    <typename T>
            inline  void    Iterable<T>::Apply (const function<void(const T& item)>& doToElement) const
            {
                RequireNotNull (doToElement);
                _GetRep ().Apply (doToElement);
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::ApplyUntilTrue (const function<bool(const T& item)>& doToElement) const
            {
                RequireNotNull (doToElement);
                return _GetRep ().FindFirstThat (doToElement, this);
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::ApplyUntilTrueStatic (bool (*doToElement) (const T& item)) const
            {
                RequireNotNull (doToElement);
                return _GetRep ().FindFirstThat (doToElement, this);
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::FindFirstThat (const function<bool(const T& item)>& doToElement) const
            {
                RequireNotNull (doToElement);
                return _GetRep ().FindFirstThat (doToElement, this);
            }
            template    <typename T>
            bool    Iterable<T>::ContainsWith (const function<bool(const T& item)>& doToElement) const
            {
                for (T i : *this) {
                    if (doToElement (i)) {
                        return true;
                    }
                }
                return false;
            }
            template    <typename T>
            template    <typename CONTAINER_OF_T>
            CONTAINER_OF_T    Iterable<T>::As () const
            {
                return CONTAINER_OF_T (this->begin (), this->end ());
            }
            template    <typename T>
            inline  typename Iterable<T>::_ReadOnlyIterableIRepReference   Iterable<T>::_GetReadOnlyIterableIRepReference () const
            {
                return _ReadOnlyIterableIRepReference (fRep_);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_Iterable_inl_ */
<commit_msg>Assertions/internal checking in Iterable wtih MOVE ctors<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_Traversal_Iterable_inl_
#define _Stroika_Foundation_Traversal_Iterable_inl_

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Traversal {

            /*
             ********************************************************************************
             *************************** Iterable<T>::_IRep *********************************
             ********************************************************************************
             */
            template    <typename T>
            inline  bool    Iterable<T>::_IRep::_IsEmpty () const
            {
                return GetLength () == 0;
            }
            template    <typename T>
            inline  void    Iterable<T>::_IRep::_Apply (_APPLY_ARGTYPE doToElement) const
            {
                RequireNotNull (doToElement);
                for (Iterator<T> i = MakeIterator (this); i != Iterable<T>::end (); ++i) {
                    (doToElement) (*i);
                }
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::_IRep::_FindFirstThat (_APPLYUNTIL_ARGTYPE doToElement, IteratorOwnerID suggestedOwner) const
            {
                RequireNotNull (doToElement);
                for (Iterator<T> i = MakeIterator (suggestedOwner); i != Iterable<T>::end (); ++i) {
                    if ((doToElement) (*i)) {
                        return i;
                    }
                }
                return end ();
            }

            /*
             ********************************************************************************
             ********************************** Iterable<T> *********************************
             ********************************************************************************
             */
            template    <typename T>
            inline  Iterable<T>::Iterable (const _SharedPtrIRep& rep) noexcept
:
            fRep_ (rep)
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
            }
            template    <typename T>
            inline  Iterable<T>::Iterable (const Iterable<T>& from) noexcept
:
            fRep_ (from.fRep_)
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
            }
            template    <typename T>
            inline  Iterable<T>::Iterable (Iterable<T>&& from) noexcept
:
            fRep_ (std::move (from.fRep_))
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
                Require (from.fRep_ == nullptr);    // after move
            }
            template    <typename T>
            inline  Iterable<T>::Iterable (_SharedPtrIRep&& rep) noexcept
:
            fRep_ (std::move (rep))
            {
                Require (fRep_.GetSharingState () != Memory::SharedByValue_State::eNull);
                Require (rep == nullptr);   // after move
            }
            template    <typename T>
            inline  Iterable<T>::~Iterable ()
            {
            }
            template    <typename T>
            inline  Iterable<T>&    Iterable<T>::operator= (const Iterable<T>& rhs)
            {
                RequireNotNull (rhs.fRep_.get ());
                fRep_ = rhs.fRep_;
                return *this;
            }
            template    <typename T>
            inline  typename Iterable<T>::_SharedPtrIRep  Iterable<T>::Clone_ (const _IRep& rep, IteratorOwnerID forIterableEnvelope)
            {
                return rep.Clone (forIterableEnvelope);
            }
            template    <typename T>
            inline  Memory::SharedByValue_State     Iterable<T>::_GetSharingState () const
            {
                return fRep_.GetSharingState ();
            }
            template    <typename T>
            inline  typename Iterable<T>::_IRep&         Iterable<T>::_GetRep ()
            {
                //EnsureNotNull (fRep_.get ());
                // subtle - but we must use the get () overload that allows passing in our Copy forward parameters
                // instead of using operator* (which doesnt allow passsing in the copy forward paramters).
                //
                // Note - our copy forward paramters are the container envelope pointer
                return *(fRep_.get (this));
            }
            template    <typename T>
            inline  const typename Iterable<T>::_IRep&   Iterable<T>::_GetRep () const
            {
                EnsureNotNull (fRep_.get ());
                return *fRep_;
            }
            template    <typename T>
            inline  const typename Iterable<T>::_IRep&   Iterable<T>::_ConstGetRep () const
            {
                EnsureNotNull (fRep_.get ());
                return *fRep_;
            }
            template    <typename T>
            inline  Iterator<T>     Iterable<T>::MakeIterator () const
            {
                return _GetRep ().MakeIterator (this);
            }
            template    <typename T>
            inline  size_t  Iterable<T>::GetLength () const
            {
                return _GetRep ().GetLength ();
            }
            template    <typename T>
            inline  bool    Iterable<T>::IsEmpty () const
            {
                return _GetRep ().IsEmpty ();
            }
            template    <typename T>
            template    <typename EQUALS_COMPARER>
            bool    Iterable<T>::Contains (const T& element) const
            {
                for (T i : *this) {
                    if (EQUALS_COMPARER::Equals (i, element)) {
                        return true;
                    }
                }
                return false;
            }
            template    <typename T>
            template    <typename RHS_CONTAINER_TYPE, typename EQUALS_COMPARER>
            bool    Iterable<T>::SetEquals (const RHS_CONTAINER_TYPE& rhs) const
            {
                /*
                 *  An extremely in-efficient but space-constant implementation. N^2 and check
                 *  a contains b and b contains a
                 */
                for (auto ti : *this) {
                    bool contained  =   false;
                    for (auto ri : rhs) {
                        if (EQUALS_COMPARER::Equals (ti, ri)) {
                            contained = true;
                            break;
                        }
                    }
                    if (not contained) {
                        return false;
                    }
                }
                for (auto ri : rhs) {
                    bool contained  =   false;
                    for (auto ti : *this) {
                        if (EQUALS_COMPARER::Equals (ti, ri)) {
                            contained = true;
                            break;
                        }
                    }
                    if (not contained) {
                        return false;
                    }
                }
                return true;
            }
            template    <typename T>
            template    <typename RHS_CONTAINER_TYPE, typename EQUALS_COMPARER>
            bool    Iterable<T>::MultiSetEquals (const RHS_CONTAINER_TYPE& rhs) const
            {
                auto    tallyOf = [] (const Iterable<T>& c, T item) -> size_t {
                    size_t  total = 0;
                    for (auto ti : c)
                    {
                        if (EQUALS_COMPARER::Equals (ti, item)) {
                            total++;
                        }
                    }
                    return total;
                };
                /*
                 *  An extremely in-efficient but space-constant implementation. N^3 and check
                 *  a contains b and b contains a
                 */
                for (auto ti : *this) {
                    if (tallyOf (*this, ti) != tallyOf (rhs, ti)) {
                        return false;
                    }
                }
                for (auto ti : rhs) {
                    if (tallyOf (*this, ti) != tallyOf (rhs, ti)) {
                        return false;
                    }
                }
                return true;
            }
            template    <typename T>
            template    <typename RHS_CONTAINER_TYPE, typename EQUALS_COMPARER>
            bool    Iterable<T>::ExactEquals (const RHS_CONTAINER_TYPE& rhs) const
            {
                Iterator<T> li  =   MakeIterator ();
                Iterator<T> le  =   end ();
                auto        ri  =   rhs.begin ();
                auto        re  =   rhs.end ();
                for (; li != le and ri != re; ++ri, ++li) {
                    if (not EQUALS_COMPARER::Equals (*li, *ri)) {
                        return false;
                    }
                }
                // only true if we get to end at the same time
                return li == le and ri == re;
            }
            template    <typename T>
            inline  bool    Iterable<T>::empty () const
            {
                return IsEmpty ();
            }
            template    <typename T>
            inline  size_t  Iterable<T>::length () const
            {
                return GetLength ();
            }
            template    <typename T>
            inline  size_t  Iterable<T>::size () const
            {
                return GetLength ();
            }
            template    <typename T>
            inline  Iterator<T> Iterable<T>::begin () const
            {
                return MakeIterator ();
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::end ()
            {
                return (Iterator<T>::GetEmptyIterator ());
            }
            template    <typename T>
            inline  void    Iterable<T>::ApplyStatic (void (*doToElement) (const T& item)) const
            {
                RequireNotNull (doToElement);
                _GetRep ().Apply (doToElement);
            }
            template    <typename T>
            inline  void    Iterable<T>::Apply (const function<void(const T& item)>& doToElement) const
            {
                RequireNotNull (doToElement);
                _GetRep ().Apply (doToElement);
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::ApplyUntilTrue (const function<bool(const T& item)>& doToElement) const
            {
                RequireNotNull (doToElement);
                return _GetRep ().FindFirstThat (doToElement, this);
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::ApplyUntilTrueStatic (bool (*doToElement) (const T& item)) const
            {
                RequireNotNull (doToElement);
                return _GetRep ().FindFirstThat (doToElement, this);
            }
            template    <typename T>
            inline  Iterator<T>    Iterable<T>::FindFirstThat (const function<bool(const T& item)>& doToElement) const
            {
                RequireNotNull (doToElement);
                return _GetRep ().FindFirstThat (doToElement, this);
            }
            template    <typename T>
            bool    Iterable<T>::ContainsWith (const function<bool(const T& item)>& doToElement) const
            {
                for (T i : *this) {
                    if (doToElement (i)) {
                        return true;
                    }
                }
                return false;
            }
            template    <typename T>
            template    <typename CONTAINER_OF_T>
            CONTAINER_OF_T    Iterable<T>::As () const
            {
                return CONTAINER_OF_T (this->begin (), this->end ());
            }
            template    <typename T>
            inline  typename Iterable<T>::_ReadOnlyIterableIRepReference   Iterable<T>::_GetReadOnlyIterableIRepReference () const
            {
                return _ReadOnlyIterableIRepReference (fRep_);
            }

        }
    }
}
#endif /* _Stroika_Foundation_Traversal_Iterable_inl_ */
<|endoftext|>