Commit f300a89c authored by rdubner's avatar rdubner

Move .legacy to ../samples-cbl-gdb. Get compilation and 'make install' working.

parent c5c11bd5
This is the island of misfit software.
The ELF and DWARF knowledge in OBMOD, for example, was too hard-won for us to
just cast it aside. But it's no longer needed in cbl-gdb.
So, it lives here.
SELFCHECK and PICGEN, in contrast, are actually a useful regression testing
programs; they compare the way cprint.py displays and enters variables to the
way that gdb and cobc do. But they broke when I eliminated OBMOD, and they
needs to be repaired.
\ No newline at end of file
*.o
*.d
obmod
odbmod.exe
/Debug
/Release
/x64
/.vs
cprint_py.h
project=obmod
CPP = g++
src = $(wildcard *.cpp)
obj = $(src:.cpp=.o)
dep = $(obj:.o=.d) # one dependency file for each source
$(project) : $(obj)
$(CPP) -o $@ $^
-include $(dep) # include all dep files in the makefile
# rule to generate a dep file by using the C preprocessor
# (see man cpp for details on the -MM and -MT options)
%.d: %.cpp
@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
c_elf.cpp : cprint_py.h
cprint_py.h : ../python/cprint.py
xxd -i ../python/cprint.py >cprint_py.h
.PHONY: clean
clean:
rm -f $(obj) $(project) $(dep) cprint_py.h
.PHONY: pregit
pregit:
dos2unix *.h
dos2unix *.cpp
dos2unix Makefile
dos2unix .gitignore
astyle -n --style=kr --indent=spaces=4 --break-return-type *.h
astyle -n --style=kr --indent=spaces=4 --break-return-type *.cpp
.PHONY : install
install :
install $(project) /usr/local/bin/
\ No newline at end of file
This diff is collapsed.
#pragma once
#ifndef __C_ELF_H
#define __C_ELF_H
#include <string>
#include <iostream>
#include <fstream>
#include <istream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <string.h>
#include <stdarg.h>
#include "utils.h"
#include "dwarf4.h"
#include "dwarf4_tags.h"
#include "die.h"
#include "elf.h"
#include "line_machine.h"
#include "cobst.h"
#include "profiler.h"
class ELF;
class SECTION_HEADER
{
private:
char *raw_data; // Local copy of raw section data.
// // section_header.size *always*
// // reflects the data size of this block.
Elf64_Xword allocated_size; // Used for expanding the block
public:
Elf64_Shdr section_header; // section header from ELF file
std::string section_header_name; // section name as indexed in .shstrtab section
SECTION_HEADER()
{
CPROFILER;
raw_data = nullptr;
allocated_size = 0;
}
~SECTION_HEADER()
{
CPROFILER;
DeleteRawData();
}
char *RawData() const
{
CPROFILER;
return raw_data;
}
void SetRawDataPointer(char *p,ULONGLONG size)
{
CPROFILER;
DeleteRawData();
raw_data = p;
section_header.sh_size = size;
allocated_size = size;
}
void DeleteRawData()
{
CPROFILER;
delete[] raw_data;
raw_data = nullptr;
section_header.sh_size = 0;
allocated_size = 0;
}
std::string GetSymbolByIndex(int index)
{
CPROFILER;
std::string retval = "<" "?" "?" ">" ;
if( index < section_header.sh_size ) {
retval = std::string(raw_data + index);
}
return retval;
}
void TrimRawData(size_t nbytes)
{
CPROFILER;
// Sometimes it is necessary, like when adding abbreviations to
// .debug_abbrev, to overwrite something like a final zero.
nbytes = std::min(nbytes,section_header.sh_size);
section_header.sh_size -= nbytes;
}
void AppendToRawData(const char *p, ULONGLONG size)
{
CPROFILER;
// Append p to raw_data
while( section_header.sh_size + size > allocated_size ) {
allocated_size = std::max(section_header.sh_size + size,allocated_size*2);
char *newp = new char[allocated_size];
memcpy(newp,raw_data,section_header.sh_size);
std::swap(raw_data,newp);
delete[] newp;
}
memcpy(raw_data + section_header.sh_size,p,size);
section_header.sh_size += size;
// Some sections have an initial length field.
if( section_header_name == ".debug_info" ) {
// Odd. This is in dwarf4.h, but doesn't seem to get picked up?
// So I don't know why I had to put this here.
extern void SetSectionLength(PCHAR &p,bool bDwarfIs64,ULONGLONG length);
bool bIsDwarf64 = *(ULONG *)raw_data == 0xFFFFFFFF;
PCHAR p = raw_data;
SetSectionLength(p,bIsDwarf64,section_header.sh_size);
}
}
};
typedef std::vector<SECTION_HEADER> VSECTION_HEADER;
class ELF
{
private:
Elf64_Ehdr elf_header;
USHORT section_version;
bool section_64;
bool bTargetIs64;
VSECTION_HEADER section_headers;
std::unordered_map<std::string,size_t> location_of_section_header_by_name;
std::unordered_map<size_t,size_t>location_of_abbreviation_element;
LNS_STATE_MACHINE lns_state_machine;
COBST_SYMBOLS cobst_symbols;
DIES debug_info_dies;
std::unordered_map<Elf64_Addr,size_t>hash_by_r_offset;
void ReadInElfHeader(std::ifstream &ifs);
void ReadInSectionHeaders(std::ifstream &ifs);
void ReadInRawSectionData(std::ifstream &ifs);
DIE GetNextDie(int &nLevel, CPCHAR &pdata, bool bIs64);
size_t AddToAbbreviations(ABBREVIATION &abbreviation);
size_t AddToAbbreviations(DW_TAG dw_tag,
bool bHasChildren,
... );
size_t BuildDie(PCHAR &pdata,
size_t &form_strp_offset,
size_t &form_exprloc_offset,
size_t abbreviation_index,
bool bDwarfIs64,
va_list valist);
size_t BuildAndAppendDie( size_t &form_strp_offset,
size_t &form_exprloc_offset,
SECTION_HEADER *debug_info,
SECTION_HEADER *relocs,
ULONGLONG abbreviation_index_of_base_type,
...);
void CreateRelocationFor(SECTION_HEADER *debug_info,
SECTION_HEADER *relocs,
size_t location_of_at_location,
size_t form_exprloc_offset,
size_t additional_offset);
ULONGLONG AddToStringTable(const std::string &sec_name,
const std::string &text);
void CreateSection(const std::string &sec_name,
ULONGLONG type,
ULONGLONG flags );
void WriteOutElfHeader(std::ofstream &ofs);
void WriteOutSectionHeaders(std::ofstream &ofs);
void WriteOutRawSectionData(std::ofstream &ofs);
public:
ELF()
{
bTargetIs64 = true;
}
~ELF()
{
}
bool IsTarget64() const
{
return bTargetIs64;
}
void ReadCobolSymbolTable(const std::string &cobst_filename);
void ReadFrom(std::string object_filename);
void WriteTo(std::string object_filename);
void DisplaySectionHeaders(std::ostream &ofs=std::cout);
void ApplyRelocations(int plus_or_minus);
size_t GetAbbreviationOffset(ULONGLONG abbreviation) const;
const char *GetAbbreviationLocation(ULONGLONG abbreviation) const;
void BuildAbbreviationIndex();
void BuildDebugInfo();
void DumpEntireDebugInfoDieTree();
void RunLineStateMachine(bool show_your_work);
void ReplaceDebugLineSection();
std::string SymbolString();
void InsertDebugScript(const std::string &python_script, const std::string &sname);
void AugmentSymbolTable();
SECTION_HEADER *GetSectionHeaderDangerous(const std::string secname)
{
CPROFILER;
SECTION_HEADER *retval = nullptr;
size_t index = GetSectionHeaderIndex(secname);
if(index != std::string::npos) {
retval = &section_headers[index];
}
return retval;
}
size_t GetSectionHeaderIndex(const std::string secname) const
{
CPROFILER;
std::unordered_map<std::string,size_t>::const_iterator it = location_of_section_header_by_name.find(secname);
if(it == location_of_section_header_by_name.end()) {
return std::string::npos;
}
return it->second;
}
const char *GetSectionDataLocation(const std::string secname) const
{
CPROFILER;
size_t index = GetSectionHeaderIndex(secname);
return section_headers[index].RawData();
}
char *GetSectionDataLocationDangerous(const std::string secname)
{
CPROFILER;
size_t index = GetSectionHeaderIndex(secname);
return section_headers[index].RawData();
}
void ReplaceASymbol(const std::string &section, const std::string &was, const std::string &is, bool whole_symbol);
void BruteForceReplace(const std::string &section, const std::string &was, const std::string &is);
};
#endif
\ No newline at end of file
#include <iostream>
#include <fstream>
#include <unordered_map>
#include "cobst.h"
#include "params.h"
#include "profiler.h"
#define EQ ==
#define AND &&
#define OR ||
using namespace std;
void COBST_SYMBOLS::ReadFrom(const string &cobst_filename)
{
CPROFILER;
ifstream ifs;
OpenOrFail(ifs,cobst_filename);
string input;
// First order of business: get a map of column headers. This means, of
// course, that any change to the header names in the cobst output will
// break this file.
getline(ifs,input);
vector<string>column_headers = Split(input,"\t");
const string SOURCE_FILE = "Source File";
const string LINE_NUMBER = "Line Number";
const string PROGRAM_NAME = "Program Name";
const string DIVISION = "Division";
const string ENTRY = "Entry";
const string SECTION = "Section";
const string PARAGRAPH = "Paragraph";
const string ASSEMBLY_SECTION = "Assembly Section";
const string ADDRESS = "Relative Address";
const string FULL_NAME = "Full Name";
const string LEVEL = "Level";
const string BASE_SYMBOL = "Base Symbol";
const string OFFSET = "Offset";
const string USAGE = "Usage";
const string LIST_TYPE = "List Type";
const string LIST_SIZE = "List Size";
const string PICTURE = "Picture";
const string OCCURS = "Occurs";
const string ATTR_TYPE = "Attr Type";
const string ATTR_DIGITS = "Attr Digits";
const string ATTR_SCALE = "Attr Scale";
const string ATTR_FLAGS = "Attr Flags";
map<string,size_t>header_columns;
for(int i=0; i<(int)column_headers.size(); i++) {
header_columns[column_headers[i]] = i;
}
// With that map, we can extract the information of interest to us:
COBST_SYMBOL prior;
for(;;) {
COBST_SYMBOL cobst_symbol;
getline(ifs,input);
vector<string>values = Split(input,"\t");
if(values.size() < 9) {
break;
}
if( values[header_columns[ASSEMBLY_SECTION]] EQ ".text" ) {
cobst_symbol.file = values[header_columns[SOURCE_FILE]];
cobst_symbol.line_number= stoull(values[header_columns[LINE_NUMBER]]);
cobst_symbol.program = values[header_columns[PROGRAM_NAME]];
cobst_symbol.division = values[header_columns[DIVISION]];
cobst_symbol.entry = values[header_columns[ENTRY]];
cobst_symbol.section = values[header_columns[SECTION]];
cobst_symbol.paragraph = values[header_columns[PARAGRAPH]];
cobst_symbol.address =
stoull(values[header_columns[ADDRESS]].substr(2),nullptr,16);
if( prior.file != cobst_symbol.file
OR prior.program != cobst_symbol.program
OR prior.entry != cobst_symbol.entry
OR prior.section != cobst_symbol.section
OR prior.paragraph != cobst_symbol.paragraph ) {
cobst_symbol.status_change = true;
}
cobst_symbols.push_back(cobst_symbol);
prior = cobst_symbol;
} else {
cobst_symbol.section = values[header_columns[SECTION]];
if( cobst_symbol.section EQ "WORKING-STORAGE"
OR cobst_symbol.section EQ "INPUT-OUTPUT"
OR cobst_symbol.section EQ "LOCAL-STORAGE"
OR cobst_symbol.section EQ "LINKAGE" ) {
cobst_symbol.program = values[header_columns[PROGRAM_NAME]];
cobst_symbol.full_name = values[header_columns[FULL_NAME]];
cobst_symbol.level = stoi(values[header_columns[LEVEL]]);
cobst_symbol.division = values[header_columns[DIVISION]];
cobst_symbol.base_symbol = values[header_columns[BASE_SYMBOL]];
cobst_symbol.offset = stoull(values[header_columns[OFFSET]]);
cobst_symbol.list_type = values[header_columns[LIST_TYPE]];
cobst_symbol.list_size = stoull(values[header_columns[LIST_SIZE]]);
cobst_symbol.picture = values[header_columns[PICTURE]];
cobst_symbol.usage = values[header_columns[USAGE]];
cobst_symbol.occurs = stoi(values[header_columns[OCCURS]]);
cobst_symbol.attr_type = (USHORT)stoul(values[header_columns[ATTR_TYPE]]);
cobst_symbol.attr_digits = (USHORT)stoul(values[header_columns[ATTR_DIGITS]]);
cobst_symbol.attr_scale = (SHORT)stoi(values[header_columns[ATTR_SCALE]]);
cobst_symbol.attr_flags = (USHORT)stoul(values[header_columns[ATTR_FLAGS]]);
}
cobst_symbols.push_back(cobst_symbol);
prior = cobst_symbol;
}
}
}
#pragma once
#include <string>
#include "utils.h"
class COBST_SYMBOL
{
public:
std::string file; // The COBOL source file
ULONGLONG line_number;// The specified line number
ULONGLONG column; // The column, if it can be divined
std::string program; // From the COBOL PROGRAM-ID
std::string division; // Procedure vs Data
std::string entry; // ...programs have entries
std::string section; // ...that might have sections
std::string paragraph; // ...that might have paragraphs
bool status_change; // Means that program.entry.section.paragraph has changed
ULONGLONG address; // Relative address
std::string full_name; // COBOL symbol name
int level; // COBOL symbol level
std::string base_symbol;// C-code base symbol for the COBOL symbol
ULONGLONG offset; // offset from the base address
std::string list_type; //
size_t list_size; // Length of data
std::string picture;
std::string usage;
int occurs;
USHORT attr_type;
USHORT attr_digits;
SHORT attr_scale;
USHORT attr_flags;
COBST_SYMBOL()
{
line_number = 0;
column = 0;
address = 0;
status_change = false;
}
};
typedef std::vector<COBST_SYMBOL>VCOBST_SYMBOLS;
class COBST_SYMBOLS
{
private:
VCOBST_SYMBOLS cobst_symbols;
public:
void ReadFrom(const std::string &cobst_filename);
size_t size() const
{
return cobst_symbols.size();
}
const COBST_SYMBOL &operator[](size_t n) const
{
return cobst_symbols[n];
}
};
\ No newline at end of file
#include "c_elf.h"
#include "die.h"
#include "profiler.h"
#define EQ ==
#define AND &&
#define OR ||
using namespace std;
string ATTRIBUTE_FORMAT_PAIR::PayloadAsString(const ELF &elf,bool with_offset) const
{
CPROFILER;
string retval;
// Use the size of payload as a default:
ULONGLONG nLength = payload.size();
LONGLONG exprloc=0x87654321;
switch(dw_form) {
case DW_FORM_addr:
break;
case DW_FORM_block2:
break;
case DW_FORM_block4:
break;
case DW_FORM_data2:
break;
case DW_FORM_data4:
break;
case DW_FORM_data8:
break;
case DW_FORM_string:
// Zero-terminated string of 8-bit characters
for(size_t i=0; i<payload.size()-1; i++) {
retval += payload[i];
}
nLength = 0;
break;
case DW_FORM_block:
break;
case DW_FORM_block1:
break;
case DW_FORM_data1:
break;
case DW_FORM_flag:
break;
case DW_FORM_sdata:
break;
case DW_FORM_strp: {
LONGLONG offset = 0;
for(size_t i=0; i<payload.size(); i++) {
offset += payload[i] << (i << 3); // I couldn't resist. It's just (i*8)
}
if( offset EQ 0x1891 ) {
cout << "Offset is " << hex << offset << endl;
}
const char *p = elf.GetSectionDataLocation(".debug_str");
p += offset;
if(with_offset) {
char ach[128];
sprintf(ach,"(0x%llx) ",(long long)offset);
retval += ach;
}
retval += p;
nLength = 0;
break;
}
case DW_FORM_udata:
break;
case DW_FORM_ref_addr:
break;
case DW_FORM_ref1:
break;
case DW_FORM_ref2:
break;
case DW_FORM_ref4:
break;
case DW_FORM_ref8:
break;
case DW_FORM_ref_udata:
break;
case DW_FORM_indirect:
// This is whacked out. The initial payload is a DW_FORM code that
// has to be processed:
cerr << "I don't understand how DW_FORM_indirect can be found in AT_FORM_PAIR::PayloadAsString()\n";
exit(1);
break;
case DW_FORM_sec_offset:
break;
case DW_FORM_exprloc: {
if(dw_at EQ DW_AT_location ) {
CPCHAR p = (CPCHAR)payload.data();
exprloc = LNS_STATE_MACHINE::ProcessSingleExpression(p,elf.IsTarget64());
}
break;
}
case DW_FORM_flag_present:
// This FORM has no actual data
retval = "flag_present";
break;
case DW_FORM_ref_sig8:
break;
default:
cerr << "switch(afp.GetForm()) processing an unknown value in AT_FORM_PAIR::PayloadAsString().\n";
cerr << "This needs to be understood.\n";
break;
}
if(nLength > 0) {
retval = "0x";
for(int i=(int)payload.size()-1; i>=0; i--) {
UBYTE hi = payload[i]>>4;
if(hi < 0x0a) {
retval += '0'+hi;
} else {
retval += 'a'-0x0a+hi;
}
UBYTE lo = payload[i] & 0xF;
if(lo < 0x0a) {
retval += '0'+lo;
} else {
retval += 'a'-0x0a+lo;
}
}
}
if( dw_at EQ DW_AT_location AND dw_form EQ DW_FORM_exprloc ) {
char ach[128];
sprintf(ach," (0x%16.16llX)",(long long)exprloc);
retval += ach;
}
return retval;
}
#pragma once
#include "profiler.h"
class ELF;
class ATTRIBUTE_FORMAT_PAIR
{
private:
DW_AT dw_at; // Decoded as per abbreviation table
DW_FORM dw_form; // Decoded as per abbreviation table
public: