Commit 8f1caf7d authored by rdubner's avatar rdubner

Modify cobst to produce source.sym.c, containing the .debug_gdb_scripts data

parent 918d65ad
......@@ -2,6 +2,7 @@
*.d
cobst
cobst.exe
cprint_py.h
/Debug
/Release
/x64
......
......@@ -14,6 +14,11 @@ $(project) : $(obj)
# (see man cpp for details on the -MM and -MT options)
%.d: %.cpp
@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
cobst.cpp : cprint_py.h
cprint_py.h : ../python/cprint.py
xxd -i ../python/cprint.py >cprint_py.h
.PHONY: clean
clean:
......
......@@ -10,6 +10,7 @@
#include "input_scan.h"
#include "profiler.h"
#include "vartree.h"
#include "cprint_py.h"
#define EQ ==
#define AND &&
......@@ -412,6 +413,139 @@ CreateCSV(PARAMETERS &params,
csv.Generate(params.csv);
}
static string ZeroIsNull(const LONGLONG &v)
{
stringstream ss;
if( v != 0 ) {
ss << v;
}
return ss.str();
}
static void
CreateSymc(PARAMETERS &params,
const COB_LABELS &cob_labels,
const VARIABLE_TREE &var_tree)
{
/* This routine puts the COBOL-identifier/C-identifier cross-reference
information into a single string that will be prepended, as a string
variable, to the cprint.py module embedded in the executable as a
.debug_script
*/
stringstream ss;
ss << "VARIABLE_STRING=\"";
// Do the line/address information from the .text in the minimal form
// used by cprint.py to figure out which program a trap has occurred in.
string current_program = "";
for(int i=0; i<cob_labels.size(); i++) {
COB_LABEL cs = cob_labels[i];
if( cs.section EQ "Linkage" ) {
// This information was previously transferred to the
// data_description information, so don't put it out here because
// it's potentially confusing.
continue;
}
if( cs.program != current_program) {
current_program = cs.program;
ss << "P|";
ss << cs.line_number << "|";
ss << cs.program;
ss << "~";
continue;
}
}
for(int i=0; i<var_tree.size(); i++) {
VAR_NODE cs = var_tree[i];
ss << "D|";
ss << cs.GetSection().substr(0,2) << "|";
ss << ZeroIsNull(cs.GetLevel()) << "|" ;
ss << cs.GetCanonicalName() << "|" ;
ss << cs.GetBaseSymbol() << "|" ;
ss << ZeroIsNull(cs.GetOffset()) << "|" ;
ss << cs.GetType().substr(0,1) << "|" ;
ss << ZeroIsNull(cs.GetSize()) << "|" ;
ss << cs.GetPicture() << "|" ;
ss << cs.GetUsage() << "|" ;
ss << ZeroIsNull(cs.GetOccurs()) << "|" ;
ss << ZeroIsNull(cs.GetAttrType()) << "|" ;
ss << ZeroIsNull(cs.GetAttrDigits()) << "|" ;
ss << ZeroIsNull(cs.GetAttrScale()) << "|" ;
ss << ZeroIsNull(cs.GetAttrFlags()) << "~";
}
ss << "\"";
ss << "\n";
// Copy over the Python script
char *py = new char[___python_cprint_py_len+1];
memcpy(py, ___python_cprint_py,___python_cprint_py_len);
py[___python_cprint_py_len] = '\0';
ss << py;
ss << "\n";
delete[] py;
/* As per https://sourceware.org/gdb/current/onlinedocs/gdb/dotdebug_005fgdb_005fscripts-section.html,
we are going to format that string in a way that reflects this example:
#include "symcat.h"
#include "gdb/section-scripts.h"
asm(
".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n"
".byte " XSTRING (SECTION_SCRIPT_ID_PYTHON_TEXT) "\n"
".ascii \"gdb.inlined-script\\n\"\n"
".ascii \"class test_cmd (gdb.Command):\\n\"\n"
".ascii \" def __init__ (self):\\n\"\n"
".ascii \" super (test_cmd, self).__init__ (\\\"test-cmd\\\", gdb.COMMAND_OBSCURE)\\n\"\n"
".ascii \" def invoke (self, arg, from_tty):\\n\"\n"
".ascii \" print (\\\"test-cmd output, arg = %s\\\" % arg)\\n\"\n"
".ascii \"test_cmd ()\\n\"\n"
".byte 0\n"
".popsection\n"
);
*/
string s = ss.str();
params.symc << "asm(" << endl;
params.symc << "\".pushsection \\\".debug_gdb_scripts\\\", \\\"MS\\\",@progbits,1\\n\"" << endl;
params.symc << "\".byte 4\\n\"" << endl;
int char_count = 0;
size_t i = 0;
while( i < s.size() ) {
if(char_count EQ 0) {
params.symc << "\".ascii \\\"";
char_count = 10 ;
}
if( char_count >= 120 ) {
params.symc << "\\n\"" << endl;
char_count = 0;
continue;
}
char ch = s[i++];
if( ch EQ '\n' ) {
params.symc << "\\\\n\\\"\\n\"" << endl;
char_count = 0;
continue;
}
if( ch EQ '\\' OR ch EQ '\"' ) {
params.symc << "\\";
char_count += 1;
}
params.symc << ch;
char_count += 1;
}
params.symc << "\".byte 0\\n\"" << endl;
params.symc << "\".popsection\\n\"" << endl;
params.symc << ");" << endl;
return;
}
int main(int argc, char *argv[])
{
PROFILER;
......@@ -500,5 +634,26 @@ int main(int argc, char *argv[])
// Create our actual useful .TAB file.
CreateCSV(params,cob_labels,variable_tree);
// Create the .sym.c file that will be compiled and linked into the
// executable, providing the text that will become the executable's
// .debug_gdb_scripts section
CreateSymc(params,cob_labels,variable_tree);
return 0;
}
/*
#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
#define STRINGX(s) #s
#else
#define STRINGX(s) "s"
#endif
#define XSTRING(s) STRINGX(s)
#define SECTION_SCRIPT_ID_PYTHON_TEXT 4
*/
\ No newline at end of file
......@@ -161,6 +161,7 @@
<ClCompile Include="vartree.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="cprint_py.h" />
<ClInclude Include="csv.h" />
<ClInclude Include="getopt.h" />
<ClInclude Include="input_scan.h" />
......
......@@ -59,5 +59,8 @@
<ClInclude Include="vartree.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="cprint_py.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>../samples/NC101A/NC101A.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>../samples/ref_test_2/rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>../samples/NC101A/NC101A.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>../samples/ref_test_2/rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>../samples/NC101A/NC101A.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>../samples/ref_test_2/rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>../samples/NC101A/NC101A.cbl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>../samples/ref_test_2/rtest.cbl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
\ No newline at end of file
......@@ -234,6 +234,7 @@ PARAMETERS GetParameters(int argc, char *argv[])
retval.cbl_lst_filename.Decode(retval.cbl_filename.Stem() + ".cbl.lst");
retval.full_csv_filename.Decode(retval.cbl_filename.Stem() + ".full.tab");
retval.csv_filename.Decode(retval.cbl_filename.Stem() + ".tab");
retval.symc_filename.Decode(retval.cbl_filename.Stem() + ".sym.c");
OpenOrFail(retval.cbl,retval.cbl_filename.WholePath());
OpenOrFail(retval.i,retval.i_filename.WholePath());
......@@ -242,6 +243,7 @@ PARAMETERS GetParameters(int argc, char *argv[])
OpenOrFail(retval.cbl_lst,retval.cbl_lst_filename.WholePath());
OpenOrFail(retval.full_csv,retval.full_csv_filename.WholePath());
OpenOrFail(retval.csv,retval.csv_filename.WholePath());
OpenOrFail(retval.symc,retval.symc_filename.WholePath());
return retval;
}
......
......@@ -85,6 +85,8 @@ public:
// // we know in it.
FILENAME csv_filename; // Our output file, destined to be read
// // downstream
FILENAME symc_filename; // The source file for the .debug_gdb_scrips
// //
std::ifstream cbl; // Streams for the above files
std::ifstream cbl_lst;
......@@ -93,6 +95,7 @@ public:
std::ifstream lst;
std::ofstream full_csv;
std::ofstream csv;
std::ofstream symc;
bool quiet;
};
......
......@@ -31,8 +31,7 @@ int main(int argc, char **argv)
elf.DumpEntireDebugInfoDieTree();
#endif
if( !params.suppress_lines )
{
if( !params.suppress_lines ) {
// Run the line number state machine to get the original information
// from cobc. We need to do this because we copy certain information
// over from, for instance, the DWARF .debug_line_info header.
......@@ -47,7 +46,7 @@ int main(int argc, char **argv)
// Run the line number state machine to see our replacements
//elf.RunLineStateMachine(false);
}
}
elf.InsertDebugScript("cprint.py",params.o_input_filename.GetFname());
......
......@@ -60,30 +60,26 @@ char const * optarg; /* argument associated with option */
#define EMSG ""
int getopt(int nargc, char * const * nargv, const char * ostr)
{
{
static char *progname = *nargv;
static char const * place = EMSG; /* option letter processing */
const char *oli; /* option letter list index */
if (optreset || !*place)
{
if (optreset || !*place) {
/* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-')
{
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (EOF);
}
if (place[1] && *++place == '-')
{
}
if (place[1] && *++place == '-') {
/* found "--" */
++optind;
place = EMSG;
return (EOF);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt)))
{
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means EOF.
......@@ -95,38 +91,32 @@ int getopt(int nargc, char * const * nargv, const char * ostr)
if (opterr && *ostr != ':')
(void)fprintf(stderr,"%s: illegal option -- %c\n", progname, optopt);
return (BADCH);
}
if (*++oli != ':')
{
}
if (*++oli != ':') {
/* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else
{
} else {
/* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) /* no arg */
{
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,"%s: option requires an argument -- %c\n",progname, optopt);
return (BADCH);
}
else
{
} else {
/* white space */
optarg = nargv[optind];
}
}
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}
return (optopt); /* dump back option letter */
}
//#define TESTING_GETOPT
#ifdef TESTING_GETOPT
......@@ -137,7 +127,7 @@ int getopt(int nargc, char * const * nargv, const char * ostr)
#include "getopt.h"
void testopt(int argc, char **argv)
{
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
......@@ -148,45 +138,43 @@ void testopt(int argc, char **argv)
optind = 1; // Only needed for repetitive starts
printf("Input: testop ");
for(int i=1; i<argc; i++)
{
for(int i=1; i<argc; i++) {
printf("%s ",argv[i]);
}
}
printf("\n");
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt);
return;
default:
abort ();
}
switch (c) {
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt);
return;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
printf("\n");
}
}
int main()
{
{
char *test1[] = {"x"};
char *test2[] = {"x","-a","-b"};
char *test3[] = {"x","-ab"};
......@@ -210,7 +198,7 @@ int main()
testopt(sizeof(test10)/sizeof(test10[0]),test10);
return 0;
}
}
/* This is what should be the output of the testing routine:
......
......@@ -19,7 +19,7 @@
using namespace std;
void FILENAME::Decode(const string &filename_)
{
{
drive.clear();
path.clear();
fname.clear();
......@@ -38,66 +38,53 @@ void FILENAME::Decode(const string &filename_)
#ifdef _WIN32
string cwd = getcwd(cwd_,sizeof(cwd_));
if(cwd.size() > 0 AND cwd[cwd.size()-1] != '\\')
{
if(cwd.size() > 0 AND cwd[cwd.size()-1] != '\\') {
cwd += '\\';
}
}
drive = cwd.substr(0,2);
default_path = Replace(cwd.substr(2),'\\',delimiter);
if(filename_.size() >= 2)
{
if(filename_.substr(0,2) EQ "\\\\")
{
if(filename_.size() >= 2) {
if(filename_.substr(0,2) EQ "\\\\") {
//This is the UNC \\server case:
size_t nslash = filename_.find('\\',2);
if(nslash != string::npos)
{
if(nslash != string::npos) {
drive = filename_.substr(0,nslash);
default_path = '\\';
filename = filename_.substr(nslash+1);
}
else
{
} else {
// There is nothing but a server name...maybe
drive = filename_;
default_path = '\\';
filename.clear();
}
}
else
{
if(filename_[1] EQ ':')
{
} else {
if(filename_[1] EQ ':') {
// He is specifying a drive. Make sure we are on the same page
// for any necessary default path:
int starting_drive = _getdrive();
if(_chdrive(toupper(filename_[0]) - 'A' + 1) EQ 0)
{
if(_chdrive(toupper(filename_[0]) - 'A' + 1) EQ 0) {
default_path = getcwd(cwd_,sizeof(cwd_));
drive = default_path.substr(0,2);
default_path = default_path.substr(2);
}
else
{
} else {
// He specified a bum drive letter. He'll get what he deserves:
// set the default to just that letter, and let the chips fall
// where they may
drive = filename_.substr(0,2);
default_path = '/';
}
}
_chdrive(starting_drive);
filename = filename.substr(2);
}
}
}
}
#else
// The Linux world will not need a drive:
drive.clear();
default_path = getcwd(cwd_,sizeof(cwd_));
if(default_path.size() >=1 AND default_path[default_path.size()-1] != delimiter)
{
if(default_path.size() >=1 AND default_path[default_path.size()-1] != delimiter) {
default_path += delimiter;
}
}
#endif
// We now have a drive (which might be empty), and
// a default path for that drive, in case we need one. Let's continue:
......@@ -105,17 +92,15 @@ void FILENAME::Decode(const string &filename_)
// Convert backslashes to frontslashes in the file name
filename = Replace(filename,'\\',delimiter);
if(filename.size() EQ 0 OR filename.size() >= 1 AND filename[0] != delimiter)
{
if(filename.size() EQ 0 OR filename.size() >= 1 AND filename[0] != delimiter) {
// The filename doesn't start with a slash, so it is a relative path.
// Incorporate the default path:
filename = default_path + filename;
}
}
size_t nfirst_slash = filename.find_first_of(delimiter);
size_t nlast_slash = filename.find_last_of(delimiter);
if(nfirst_slash != string::npos)
{
if(nfirst_slash != string::npos) {
nlast_slash += 1;
// The path will be delimited, front and back, by slashes. For
......@@ -123,23 +108,19 @@ void FILENAME::Decode(const string &filename_)
path = filename.substr(nfirst_slash,nlast_slash-nfirst_slash);
size_t nextension_dot = filename.find_last_of('.');
if(nextension_dot != string::npos AND nextension_dot >= nlast_slash)
{
if(nextension_dot != string::npos AND nextension_dot >= nlast_slash) {
fname = filename.substr(nlast_slash,nextension_dot-nlast_slash);
ext = filename.substr(nextension_dot);
}
else
{
} else {
fname = filename.substr(nlast_slash);
}
}
}
}
#ifdef _DEBUG
void DecodeTest()
{
vector<string>tests =
{
{
vector<string>tests = {
"",
".",
"/",
......@@ -166,11 +147,10 @@ void DecodeTest()
"d:path/fname",
"d:path/fname.",
"d:path/fname.ext",
};
};
FILENAME fn;
for(vector<string>::const_iterator it=tests.begin(); it!=tests.end(); it++)
{
for(vector<string>::const_iterator it=tests.begin(); it!=tests.end(); it++) {
fn.Decode(*it);
cout << "\"" << *it << "\"" << " ==> ";
cout << "\"" << fn.drive << "\"" << " + ";
......@@ -179,12 +159,12 @@ void DecodeTest()
cout << "\"" << fn.ext << "\"" << " ==> ";
cout << "\"" << fn.WholePath() << "\"" << " ";
cout << endl;
}
}
}
#endif
static void Usage()
{
{
cerr << "sfix version " VERSION "\n";
cerr << "\n";
cerr << "usage: sfix input.s output.s file.c file.cbl";
......@@ -196,41 +176,38 @@ static void Usage()
cerr << " -q quiet (suppresses version display on entry)\n";
cerr << " -v displays version information and exits\n";
cerr << "\n";
}
}
static void Version()
{
{
cerr << "obmod version " VERSION "\n";
exit(1);
}
}
void OpenOrFail(std::ifstream &ifs,const std::string &fname,std::ios_base::openmode mode/* = std::ifstream::in*/)
{
{
ifs.open(fname,mode);
if(!ifs.is_open())
{
if(!ifs.is_open()) {
cerr << "Failed to open input file \"" << fname << "\"" << endl;
exit(1);
}
}
}
void OpenOrFail(std::ofstream &ofs,const std::string &fname,std::ios_base::openmode mode/* = std::ofstream::out*/)
{
{
ofs.open(fname,mode);
if(!ofs.is_open())
{
if(!ofs.is_open()) {
cerr << "Failed to open output file \"" << fname << "\"" << endl;
exit(1);
}
}
}
PARAMETERS GetParameters(int argc, char *argv[])
{
if(argc != 5)
{
{
if(argc != 5) {
Usage();
exit(1);
}
}
PARAMETERS retval;
......@@ -238,26 +215,24 @@ PARAMETERS GetParameters(int argc, char *argv[])
string s_output_parameter;
int c;
retval.quiet = false;
while ((c = getopt (argc, argv, "qv")) != -1)
{
switch (c)
{
case 'v':
Version();
break;